嵌入式linux閘道器程式

Wlain發表於2017-06-14

實現的功能:

使用linuxC語言通過串列埠程式設計和Socket程式設計,以及解析從串列埠收到的資料,並且把資料封裝成http格式通過post方式可以實現遠端傳送資料到伺服器,並且能夠接收伺服器傳送過來的命令。
關於HTTP請求報文格式
這裡寫圖片描述
關鍵程式碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h> 
#include <string.h>
#include <netdb.h>
#include "cssl.h"

//全域性變數這邊設定裝置地址,IP,埠號,以及sockfd
char* dev_path;
char* ip = NULL;
int port;
int sockfd;
//把資料封裝成http格式,並且通過post方式傳送溫溼度資料
void sendDatawenshidu(uint8_t *buf,int length)
{
    printf("buf:%s\n",buf);
    //介面
    char page[] = "addWendu";  
    char content[4096];  
    char content_page[50];  
    char content_host[50];  
    char content_len[50]; 
    //1請求行
    sprintf(content_page,"POST /%s HTTP/1.1\r\n",page);  
    /*2.請求頭部
    /Host:請求的主機名,允許多個域名同處一個IP地址,即虛擬主機。
    */
    sprintf(content_host,"HOST: %s:%d\r\n",ip,port);  
    /*4.請求資料
    /請求資料不在GET方法中使用,而是在POST方法中使用。
    /POST方法適用於需要客戶填寫表單的場合。與請求資料相
    /關的最常使用的請求頭是Content-Type和Content-Length。
    */
    char content_type[] = "Content-Type: application/x-www-form-urlencoded\r\n";  
    sprintf(content_len,"Content-Length: %d\r\n\r\n",strlen(buf));  
    sprintf(content,"%s%s%s%s%s",content_page,content_host,content_type,content_len,buf);  
    send(sockfd,content,strlen(content),0);  

}
//把資料封裝成http格式,並且通過post方式傳送光照值資料
void sendDataguangzhao(uint8_t *buf,int length)
{
    printf("buf:%s\n",buf);
    char page[] = "Guangzhao";  
    char content[4096];  
    char content_page[50];  
    char content_len[50];  
    char content_host[50]; 
    sprintf(content_page,"POST /%s HTTP/1.1\r\n",page);  
    sprintf(content_host,"HOST: %s:%d\r\n",ip,port);  
    char content_type[] = "Content-Type: application/x-www-form-urlencoded\r\n";  
    sprintf(content_len,"Content-Length: %d\r\n\r\n",strlen(buf));  
    sprintf(content,"%s%s%s%s%s",content_page,content_host,content_type,content_len,buf);  
    send(sockfd,content,strlen(content),0);  
}
//把資料封裝成http格式,並且通過post方式傳送可燃氣體值資料
void sendDataGas(uint8_t *buf,int length)
{
    printf("buf:%s\n",buf);
    char page[] = "Gas";  
    char content[4096];  
    char content_page[50];  
    char content_host[50];
    char content_len[50]; 
    sprintf(content_page,"POST /%s HTTP/1.1\r\n",page);       
    sprintf(content_host,"HOST: %s:%d\r\n",ip,port);  
    char content_type[] = "Content-Type: application/x-www-form-urlencoded\r\n";   
    sprintf(content_len,"Content-Length: %d\r\n\r\n",strlen(buf));  
    sprintf(content,"%s%s%s%s%s",content_page,content_host,content_type,content_len,buf); 
    send(sockfd,content,strlen(content),0);  
}
//回撥函式,列印串列埠收到的資料的資訊,在這個方法中對串列埠收到的資料進行解析,並且呼叫通過socket傳送資料給伺服器
static void callback(int id, uint8_t *buf,int length)    
{
    int i;
    char dtype[2],data[50];
    printf("the date from serial:%s\n", buf);
    printf("\nread serial success:  length = %d\n", length); 
    sprintf(dtype,"%d",buf[2]);
    switch(dtype[0]){
    case '1':
        sprintf(data,"wendu=%d&shidu=%d",buf[5],buf[6]);
        puts(data);
        sendDatawenshidu(data,strlen(data));
        break;
    case '2':
        sprintf(data,"gz=%d",buf[5]);
        puts(data);
        sendDataguangzhao(data,strlen(data));
        break;
    case '3':
        sprintf(data,"gs=%d",buf[5]);
        puts(data);
        sendDataGas(data,strlen(data));
        break;
    default:
        puts("the date is error"); 
        break;
    }
}

int main( int argc, char **argv ){  
    dev_path = (char*)argv[1];
    ip  = (char*)argv[2];
    port = atoi(argv[3]);
    char buffer[64];
    if( argc < 4 ){
        fprintf( stderr,"usage: %s dev_path,ip and post\n",argv[0] );
        exit(1);
    }
    //serial part串列埠部分
        cssl_t *ser;     
        cssl_start();
        ser=cssl_open(dev_path,callback,0,38400,8,0,1);   
        if (!ser){
                printf("%s\n",cssl_geterrormsg());
        }
        printf("Serial connection successful, DEV = %s\n", dev_path);
    //create socket
    //建立socket 建立一個sock連線
    sockfd = socket( AF_INET,SOCK_STREAM,0 );

    if ( sockfd < 0 )
    {
        fprintf( stderr, "socket:%s\n", strerror(errno));
        exit(1);        
    }
    else{
        printf("success to connect the service\n");
    }

    struct sockaddr_in sockaddr;
    //設定連線資訊結構
    memset( &sockaddr,0,sizeof(sockaddr) );
    sockaddr.sin_family = AF_INET;
    sockaddr.sin_port = htons ( atoi (port) );
    inet_pton(AF_INET,ip,&sockaddr.sin_addr.s_addr);
    socklen_t len = sizeof(sockaddr);
    //連線到遠端伺服器 
    if( connect(sockfd,(struct sockaddr*)&sockaddr,len) <0 ){
        fprintf(stderr, "connect: %s\n", strerror(errno) );
        exit(1);
    }

    //receive from service :
    memset( buffer,0,sizeof(buffer) );
    ssize_t n;
    while(1){
        if( (n = read(sockfd,buffer,1024)) > 0) {
            printf("receive from service :");
            puts(buffer);
            printf("\n");
            cssl_putstring(ser,buffer);
            printf("the serial receive the commend from service  !\n");
        }       
    }
    for(;;);
    close(sockfd);
    return 0;
}

這裡寫圖片描述
具體詳細的專案程式碼可以到筆者github倉庫下載:https://github.com/Wlain/-linuxC-Socket-http-post-.git

相關文章