移*動互*聯網數*據採*集系*統

 

//======================================================node

/***********移動互聯網數據採集系統**************
  >功能:
  >    1:項目分爲服務器、客戶端;服務器交互對象爲客戶端及WATCHER開發板
  >    2:客戶端功能:註冊、登錄、退出、刪除、查詢、控制及設置功能
  >    3:服務端功能:客戶管理、更新數據庫、數據管理排序等
  >設計關鍵詞:
  >    內核鏈表(數據保存/排序/打印)、數據庫(全部數據保存位置)、自定義協議(服務器與WATCHER板交互)、
  >    Json協議(服務器與客戶端交互)、非堵塞(超時檢測)、TCP協議、線程(新建線程實現)、心跳檢查(2分鐘)
  >WATCHER開發板智能控制協議主要指令:
  >     ①RGB燈光控制指令/RGB燈光控制反饋指令,②溫溼度查詢指令/溫溼度查詢反饋指令
  >     ③光照強度查詢指令/光照強度查詢反饋指令,④時鐘設置指令/時鐘設置反饋指令
  >     ⑤鬧鐘設置指令/ 鬧鐘設置反饋指令,⑥鬧鐘查詢指令/鬧鐘查詢反饋指令
  >
 ***********移動互聯網數據採集系統(ser)**************/

#include"data_collect.h"

//=====================消息類型=====================================
proto ptype[] = {                                        
    {QUERY_INFORMATION, query_information}            
    ,                            /*查詢*/            
#if 0                                                
        {CONTROL_LAMPLIGHT, control_lamplight}            
    ,                            /*控制*/            
        {SET_ATTRIBUT, set_attribut}                    
    ,                            /*設置*/            
#endif                                                
        {CLIENT_LOGIN, server_check_login}                
    ,                            /*登錄驗證*/        
        {CLIENT_REGISTER, register_new_client}            
    ,                            /*註冊*/            
        {CLIENT_EXIT, client_exit}                        
    ,                            /*客戶退出*/        
#if 0                                                
        {CLIENT_DELETE, client_delete}                    
    ,                            /*客戶刪除*/        
        {TGB_LAMP_SET, tgb_lamp_set}                    
    ,                            /*tgb燈*/            
#endif                                                
        {TEMP_HUMIDITY_QUERY, temp_humidity_query}        
    ,                            /*溫溼度*/            
        {LIGHT_INTENSITY_QUERY, light_intensity_query}    
    ,                            /*光照強度*/        
#if 0                                                
        {TIME_SET, time_set}                            
    ,                            /*時鐘設置*/        
        {CLOCK_SET, clock_set}                            
    ,                            /*鬧鐘設置*/        
        {CLOCK_QUERY, clock_query}                        
    ,                            /*鬧鐘查詢*/                
        {CONTROL_FEEDBACK, control_feedback}                            
    ,                            /*控制反饋*/        
        {QUERY_FEEDBACK, query_feedback}                        
    ,                            /*查詢反饋*/
#endif            
        {0, 0}                                            
};

//=================主函數(main)入口===========================
int main(int argc, char *argv[])
{
    int listen_fd;
    int ret;
    state_seq = 0;
    pthread_t tid = 0;
    devboard_thr_online = 0;    //須要用自動查詢時候改成0
    int line_num = 0;                    //新建一個鏈表其值加1

    /*=======信號處理函數、語句(時鐘、退出)======
      ===============================================*/

    //=====1,create a tcp socket===========
    listen_fd = socket(AF_INET,SOCK_STREAM,0);    //socket建立特殊文件描述符,IPV4,字節流(TCP協議)
    if(listen_fd <0){
        perror("socket");
        exit(1);
    }

    //=====2,setsockopt-- set internet attribute====
    int b_reuse = 1;    
    if(setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR,&b_reuse,sizeof(int)) == -1)    //設置屬性,容許重用本地地址和端口
        printf("server setsockopt()  error");     //原爲err

    //=====3, bind port and addr============
    struct sockaddr_in srv_addr;     //定義綁定時的結構體,結構體包含本身的族類型、IP、端口及必定填充區域
    bzero (&srv_addr, sizeof (srv_addr));     //對結構體清零
    srv_addr.sin_family = AF_INET;    //地址族IPV4
    srv_addr.sin_port = htons(SERV_PORT);    //端口號轉換host to network short,默認值9999
    srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);     //指定對方IP號爲任意IP都可
    ret = bind(listen_fd,(struct sockaddr *)&srv_addr,sizeof(srv_addr));    //bing綁定(在本身打開的文件描述符listen_fd上,綁定本身的端口號及指定對方可鏈接的ip號)
    if( ret <0 ){
        perror("bind error");
        exit(1);
    }

    //=====4, listen-- set max connection number======
    if(listen(listen_fd,QUEUELEN) == -1){    //設置同一時間最多可鏈接5個客戶端    
        perror("listen error\n");
        exit(1);
    }

    fprintf(stderr,"server waiting client connection ......OK\n");

    //=====五、初始化內核鏈,設置鏈表、select、accept參數變量=====

    //=====a)定義內核鏈表變量、初始化鏈表=====
    struct cli_info mylist;        // 定義一個結構體變量(包含內核鏈表成員)
    INIT_LIST_HEAD(&mylist.list);    // 初始化鏈表頭
    struct cli_info *tmp = NULL;    //定義結構體指針(包含內核鏈表成員)
    struct list_head *pos,*q;    //定義遍歷內核鏈表用的臨時指針

    //=====b)定義select及accept參數變量=====
    fd_set rset;    //定義數組集合,存放文件描述符,結構體數組成員在select()先後會變化
    int maxfd = -1;        //定義select()的參數(最大文件描述符號,計算rset數組最大位長度)
    struct timeval tout;    //select超時堵塞設置
    int new_fd = -1;    //定義accept鏈接時建立的新文件描述符變量
    //pthread_t tid;    //定義一個線程?????????????????
    struct sockaddr_in cli_addr;    //定義文件描述符屬性的結構體,結構體包含本身的族類型、IP、端口及必定填充區域

    /*=====六、循環,內核鏈表對全部鏈接客戶端的結構體進行鏈接,
      select監控有數據的客戶,對已鏈接有數據客戶端創建線程處理需求==*/
    while(1){
        //===a)select參數的變量賦初值====
        tout.tv_sec = 0;    //設置select等待超時爲2s
        tout.tv_usec = 0;
        FD_ZERO(&rset);        //清空rset數組隊列
        FD_SET(listen_fd,&rset);    //把fd加入到rset數組中,seleten時監控是否有新鏈接
        maxfd = listen_fd;    //改變rset數組最大位長度

        //===b)經過內核鏈表,遍歷用戶屬性結構體,把創建好鏈接的fd加入到rset,同時把maxfd更新爲值最大的fd====
        list_for_each_safe(pos,q,&mylist.list){
            tmp = list_entry(pos,struct cli_info,list);        //tmp指向遍歷的某一項結構體數據
            FD_SET(tmp->conn_fd,&rset);        //將包含內核鏈表的結構體內成員(文件描述符)加入到rset數組中
            if(maxfd < tmp->conn_fd){
                maxfd = tmp->conn_fd;    //改變rset數組最大位長度
            }        
            if(devboard_thr_online == 1){        //若是開發板線程不在線(即有線程正在向開發板發送數據),則再也不另外新建線程
                if (tmp->conn_addr.sin_addr.s_addr == inet_addr(BOARD_IP)) {    //若是開發板有鏈接,則建立線程,等等兩秒查詢一次,並寫入數據庫
                    if ((pthread_create (&tid, NULL, board_pthreads, (void *)tmp)) == -1)     
                        printf ("server pthread_create() 2  error");     
                }
            }
        }


        //===c)調用select多路複用監控函數,調用後有數據的鏈接將保留在select數組內=====
        ret = select(maxfd+1, &rset, NULL, NULL, &tout);     //多路複用監控函數,設置讀端

        //===d)accept,是否有新的鏈接請求過來(給新鏈接申請空間並加入內核鏈表)======
        socklen_t len = sizeof(struct sockaddr_in);
        if (FD_ISSET (listen_fd, &rset)) {
            new_fd = accept (listen_fd, (struct sockaddr *) &cli_addr, &len);        /* accept()處理新的鏈接 */
            if (new_fd < 0) {
                perror ("accept");
            }
            else{    //若鏈接成功,則把對新鏈接申請空間,並將鏈接加入內核鏈表
                printf ("new client coming..cli ip = %s, port(%d)\n", inet_ntoa (cli_addr.sin_addr), ntohs (cli_addr.sin_port));
                tmp = (struct cli_info *)malloc(sizeof(struct cli_info)); /*把conn_fd加入到cli_info的鏈表裏面 */
                if(!tmp) {
                    perror("malloc");
                }
                else{    //填充tmp指向的客戶屬性結構體 
                    list_add (&(tmp->list), &(mylist.list));  //把tmp->list加入用戶信息的鏈表中
                    tmp->head = &mylist.list;    //創建線程後,鏈表成員退出(即刪除)時使用
                    tmp->conn_fd = new_fd;        //將鏈接的新文件描述符conn_fd,賦值給新申請的結構體成員tmp->conn_fd
                    tmp->conn_addr = (struct sockaddr_in )cli_addr;
                    line_num++;
                    tmp->num = line_num;
                    printf ("1,tmp->conn_fd =%d,tmp->num =%d\n",tmp->conn_fd,tmp->num);        
                }
            }
        }
        /*====e)已經創建好鏈接的客戶端是否有送過來數據 =============*/
        /*遍歷內核鏈表,依次判斷鏈表項中的conn_fd上是否有數據,若有,則讀出來處理*/
        list_for_each_safe (pos, q, &mylist.list) {
            tmp = list_entry (pos, struct cli_info, list); //tmp指向遍歷到的某一項結構體數據
            if(FD_ISSET(tmp->conn_fd, &rset)) { /* 已創建鏈接的客戶端fd上有數據*/
                if ((pthread_create (&tid, NULL, pthreads, (void *)tmp)) == -1)     //爲能傳鏈表頭
                    printf ("server pthread_create() 2  error");     //原爲err
                printf("已建立一個新線程,其鏈接通訊時的new_fd = %d\n",tmp->conn_fd);    
                usleep(200000);    //不睡眠,若是有數據就會建立線程進20個,緣由尚待進一步查找??
            }
        }

    }
    close(listen_fd);
    return 0;
}

struct stu_info st;    //??????????????????????????????????????????

void *board_pthreads(void *arg)
{
    pthread_detach (pthread_self ());     //設置線程屬性分離
    struct cli_info *client_attr = ((struct cli_info *)arg);    //將arg(即主函數有數據的鏈接屬性結構體tmp)的地址賦值給tmp
    int send_num,ret;
    unsigned char recv_buf[CMD_MAX_LEN];
    struct stu_info st;
    devboard_thr_online = 0;

    auto_query = (auto_query)%255+1;            //發送序列號,可設置若相同則不接受
    printf("AUTO_QUERT_TIME/U_SECOND=%d\n",(AUTO_QUERT_TIME*1000000)/U_SECOND);    
    for(send_num=0;send_num<(AUTO_QUERT_TIME*1000000)/U_SECOND;send_num++)        //若發送SEND_NUM次後對方仍然未接收到數據則跳出(接收失敗)
    {
        printf("進入發送循環\n");
        send_dev_board(client_attr);
        usleep(U_SECOND);            //發送後、等待U_SECOND us再接收數據

        bzero (recv_buf, CMD_MAX_LEN);    //將輸入變量清零
        do {
            ret = recv (client_attr->conn_fd, recv_buf, CMD_MAX_LEN - 1, MSG_DONTWAIT);
        } while (ret < 0 && EINTR == errno);
        if (ret < 0){
            printf("send num = %d\n",send_num);
        }else{
            string_to_stu(&st,recv_buf);     //拆包到st結構體
            recv_dev_board(&st);
            break;
        }
    }
    if(send_num<(AUTO_QUERT_TIME*1000000)/U_SECOND){
        printf("package information:st.flag=0x%x,st.len=0x%x,st.cmd=0x%x,st.seq=0x%x,\nst.pac_data[0]=0x%x,st.pac_data=%s,st.bcc=0x%x\n",
                st.flag,st.len,st.cmd,st.seq,st.pac_data[0],st.pac_data,st.bcc);
        printf("當前時間%s:,當前溫度爲%d,當前溼度爲%d\n",dev_board_data.data_time,st.pac_data[2],st.pac_data[4]);
    }else
        printf("\n\n已鏈接,但未接收到開發板上信息\n\n\n");

    if(AUTO_QUERT_TIME >  U_SECOND*send_num)
        sleep(AUTO_QUERT_TIME - U_SECOND*send_num);

    devboard_thr_online = 1;

    pthread_exit(0);        
}

void *pthreads (void *arg)
{
    pthread_detach (pthread_self ());     //設置線程屬性分離
    struct cli_info *client_attr = ((struct cli_info *)arg);    //將arg(即主函數有數據的鏈接屬性結構體tmp)的地址賦值給tmp
    unsigned char buf[BUFSIZ];    //定義緩衝區數組變量
    int ret = -1;
    struct stu_info st;    //拆包後結構體
//    printf ("**********************tmp->num =%d\n",client_attr->num);     //若是不註釋,此處不斷創線程打印,不知何故??

    assert (client_attr);
    if (!client_attr)
        pthread_exit(0);        
    do {
        ret = recv (client_attr->conn_fd, buf, BUFSIZ-1, 0);    //recv()接收數據
    } while (ret < 0 && EINTR == errno);
    if (ret < 0){
        perror("recv");
        pthread_exit(0);    
    }
//    printf ("555*****tmp->num =%d\n",client_attr->num);     //若是不註釋,此處不斷創??????????????    
    char addr[50]={0};
    strcpy(addr,inet_ntoa(client_attr->conn_addr.sin_addr));
//    printf("send addr = %s \n\n",addr);        ????????????????????????????????????????????????????????
    //======不然爲客戶發送的溫溼度查詢指令,需給開發板發送指令收到命令後,反饋該客戶溫溼度值===============    
    struct list_head *pos,*q;    //定義遍歷內核鏈表用的臨時指針    
    struct cli_info *tmp = NULL;    //定義結構體指針(包含內核鏈表成員)
#if 1
    if(client_attr->num == 1) {
        printf ("*******************接收到開發板反饋的數據*******************\n"); 
        string_to_stu_tmep(&st,buf);
        recv_dev_board(&st);
        recv_content(buf);        //打印接收內容
        printf("當前時間%s:,當前溫度爲%d,當前溼度爲%d\n\n",dev_board_data.data_time,st.pac_data[2],st.pac_data[4]);
        pthread_exit(0);
        }
//    }
#else
    pos = (client_attr->head)->next;
    pos = pos->next; 
    tmp = list_entry (pos, struct cli_info,list); //client_attr指向遍歷到的某一項結構體數據
if(tmp->list.next == client_attr->list.next){
    printf ("\n1  接收到開發板反饋的數據\n\n"); 
    string_to_stu_tmep(&st,buf);
    recv_dev_board(&st);
            
    recv_content(buf);    //打印接收內容
    printf("package information:st.flag=0x%x,st.len=0x%x,st.cmd=0x%x,st.seq=0x%x,\nst.pac_data[0]=0x%x,st.pac_data=%s,st.bcc=0x%x\n",
            st.flag,st.len,st.cmd,st.seq,st.pac_data[0],st.pac_data,st.bcc);
    printf("當前時間%s:,當前溫度爲%d,當前溼度爲%d\n",dev_board_data.data_time,st.pac_data[2],st.pac_data[4]);
            
    pthread_exit(0);
}
#endif
    
    
    printf("*******************不是開發板發過來的數據*******************\n");
    string_to_stu(&st,buf);     //拆包到st結構體

#if 0    
    printf("buf=%s\n",buf);
    printf("buf[2]=%d\n",(int)buf[2]);
    printf("buf[4]=%d\n",buf[4]);
    printf("buf+5=%d\n",(int)buf[5]);
    printf("buf[6]=%d\n",buf[6]);
//#else
    printf("sizeof(start_h): %d\n", sizeof(buf[0]));
    printf("sizeof(cmd): %d\n", sizeof(buf[4]));
    printf("start_h 0: 0x%x\n", buf[0]); /* 包頭(共2字節),此處爲高位字節 */
    printf("start_l 1: 0x%x\n", buf[1]); /* 包頭(共2字節),此處爲高位字節 */
    printf("len_h   2: 0x%x\n", buf[2]); /* 包長度(共2字節),此處爲高位字節 */
    printf("len_l   3: 0x%x\n", buf[3]); /* 包長度(共2字節),此處爲低位字節 */
    printf("cmd     4: 0x%x\n", buf[4]); /* 命令類型(共1字節),由於查詢溫溼度,因此查詢指令填0x80 */
    printf("seq     5:   %x\n", buf[5]); /* seq爲消息序,兩個做用:消息重發和識別客戶端 */
    printf("data[0] 6:   %x\n", buf[6]); /* 設備類型,要查詢溫溼度傳感器,因此爲0x02 */
    printf("data[1] 7:   %x\n", buf[7]); /* 反饋結果(成功:0x00,BCC校驗錯誤:0x01,失敗:0x02,模式錯誤:0x03,指令非法:0xFF*/
    printf("data[2] 8:   %x\n", buf[8]); /* 溼度整數部分 */
    printf("data[3] 9:   %x\n", buf[9]); /* 溼度小數部分 */
    printf("data[4] 10:  %x\n", buf[10]); /* 溫度整數部分 */
    printf("data[5] 11:  %x\n", buf[11]); /* 溫度小數部分 */
    printf("bcc 7   12:  %x\n", buf[12]); /* 校驗值 */    

    printf("package information:st.flag=0x%x,st.len=0x%x,st.cmd=0x%x,st.seq=0x%x,\nst.pac_data[0]=0x%x,st.bcc=0x%x\n",
            st.flag,st.len,st.cmd,st.seq,st.pac_data[0],st.bcc);
#endif

    int i = 0;
    for (i = 0; ptype[i].fun_flag != 0; i++) {
        if (st.pac_data[0] == ptype[i].fun_flag) {
            ptype[i].fun (&st,client_attr);        //根據發送類型,處理相關內容函數
            break;
        }
    }
    printf("*******************關閉遍歷的線程*******************\n");    //????????

    pthread_exit(0);    
}


//#########裝拆包處有問題8.10

//sleep(2);            //??????????????????????????????????????????????????????????????????
//printf("1_ 哪裏出錯了??\n");    //????????????????????????????????????????????????????????????????????????        
sev_data_collect.c

//======================================================linux

/***********移動互聯網數據採集系統**************
  >project name: move internet data collect system
  >Author: 夏敏、甘香鵬、程健、殷文傑
  >Created Time :2016/08/04 18:20

  >功能:
  >    1:項目分爲服務器、客戶端;服務器交互對象爲客戶端及WATCHER開發板
  >    2:客戶端功能:註冊、登錄、退出、刪除、查詢、控制及設置功能
  >    3:服務端功能:客戶管理、更新數據庫、數據管理排序等
  >設計關鍵詞:
  >    內核鏈表(數據保存/排序/打印)、數據庫(全部數據保存位置)、自定義協議(服務器與WATCHER板交互)、
  >    Json協議(服務器與客戶端交互)、非堵塞(超時檢測)、TCP協議、線程(新建線程實現)、心跳檢查(2分鐘)
  >WATCHER開發板智能控制協議主要指令:
  >     ①RGB燈光控制指令/RGB燈光控制反饋指令,②溫溼度查詢指令/溫溼度查詢反饋指令
  >     ③光照強度查詢指令/光照強度查詢反饋指令,④時鐘設置指令/時鐘設置反饋指令
  >     ⑤鬧鐘設置指令/ 鬧鐘設置反饋指令,⑥鬧鐘查詢指令/鬧鐘查詢反饋指令
  >
 ***********移動互聯網數據採集系統(ser)**************/
#include"data_collect.h"


/*******************************************
//==============溫溼度查詢,將字符串轉換成數據包==================
void stu_to_sti(unsigned seq,unsigned char *buf)
{
buf[0] =0xff;    //flag頭部首字節,開始標誌位固定爲0xff
buf[1] =0xff;    //flag頭部次字節
buf[2] =0x00;    //length首字節,length爲協議長度:從cmd開始到正規協議結束所佔用字節數;
buf[3] =0x04;    //length次字節
buf[4] =0x80;    //cmd指令類型(控制/控制反饋/查詢/查詢反饋)
buf[5] =(unsigned char)seq;        //序號,發送者給出的序號,回覆必須把序號返回發送者,以保障順序正確性。
buf[6] =0x02;    //數據,其中data[0]爲數據類型
}


// 填充協議: 命令會有9個本身的開銷(包含最後的'\0'字符) 
buf[0] = PACK_HEAD;            //head 

buf[1] = cmd_type;            // cmd_type 

buf[2] = 0x0;                //2字節長度,高位在前,低位在後 
buf[3] = cmd_len & 0xff;

if (cmd_len > 255) {
buf[2] = ((cmd_len & 0xff00) >> 8);
//  buf[3] = cmd_len & 0xff;
 ***********************************************/

//============(拆包,通用)將開發板上的包變成結構體======================
void string_to_stu(struct stu_info *st,unsigned char *buf)
{
    memset(st,0,sizeof(st));
    int i;
    printf("*0_******通用協議收包buf[0]=0x%x\n*********",buf[0]);
    st->flag = buf[1];        //flag頭部,開始標誌位固定爲0xffff
    if(buf[0]>0)            //判斷flag頭部高八位是否有值
        st->flag += buf[0]*256;        
    printf("*1_******通用協議收包buf[0]=0x%x\n*********",buf[0]);

    st->len = buf[3];        //length長度,length爲協議長度:從cmd開始到正規協議結束所佔用字節數;
    if(buf[2]>0)            //判斷length長度高八位是否有值
        st->len += buf[2]*256;        

    st->cmd = buf[4];    //cmd指令類型(控制/控制反饋/查詢/查詢反饋)
    st->seq = buf[5];    //序號,發送者給出的序號,回覆必須把序號返回發送者,以保障順序正確性。
//    memcpy (st->pac_data, buf+6, st->len);    //客戶/開發板數據,其中data[0]爲數據類型
    for(i=0;i < st->len; i++){
        st->pac_data[6+i] = buf[2];
    }
    st->pac_data[st->len] = '#';
    st->bcc = buf[st->len+6];    //校驗和:數據校驗,從length到data數據的異或校驗和
#if 1
    printf("*******通用協議收包buf[0]=0x%x\n*********",buf[0]);
    printf("buf[0]=0x%x\n",buf[0]);
    printf("buf[1]=0x%x\n",buf[1]);
    printf("buf[2]=0x%x\n",buf[2]);
    printf("buf[3]=0x%x\n",buf[3]);
    printf("buf[4]=0x%x\n",buf[4]);
    printf("buf[5]=0x%x\n",buf[5]);
    printf("buf[6]=0x%x\n",buf[6]);
    printf("buf[7]=0x%x\n",buf[7]);
    printf("buf[8]=0x%x\n",buf[8]);
    printf("buf[9]=0x%x\n",buf[9]);
    printf("buf[10]=0x%x\n",buf[10]);
    printf("buf[11]=0x%x\n",buf[11]);
    
    printf("buf[len+6]=0x%x\n",(int)buf[st->len+6]);
    printf("len=%d\n",st->len);        //?????????????????????????????????????
    printf("st->pac_data[0]=%c\n",st->pac_data[0]);        //?????????????????????????????????????
//    printf("拆解後的字符串=%s\n",st->pac_data);        //????????????????????    
    printf("st->bcc=%x\n",(int)st->bcc);
#endif
}

//==============(封包,通用)將字符串轉換成數據包==========
void stu_to_sti(unsigned char cmd,unsigned char seq,unsigned char *data,unsigned char *buf)
{
    int len =0;
    for(len=0;data[len] != '#'; len++);
    
    bzero(buf,len+20);
    
    printf("buf[6]=0x%x\n",buf[6]);
    printf("buf[7]=0x%x\n",buf[7]);
    printf("buf[8]=0x%x\n",buf[8]);
    printf("buf[9]=0x%x\n",buf[9]);
    printf("buf[10]=0x%x\n",buf[10]);
    printf("buf[11]=0x%x\n",buf[11]);
    
    buf[0] =0xff;    //flag頭部首字節,開始標誌位固定爲0xffff
    buf[1] =0xff;    //flag頭部次字節
    if(len > 255){
        buf[2] = len/256;
        buf[3] = len - buf[3]*256;
    }else{
        buf[2] = 0;
        buf[3] = len;        
    }
    buf[4] =cmd;    //cmd指令類型(控制/控制反饋/查詢/查詢反饋)
    buf[5] =seq;        //序號,發送者給出的序號,回覆必須把序號返回發送者,以保障順序正確性。
//    memcpy (buf+6,data,len);    //客戶/開發板數據,其中data[0]爲數據類型
    int i;
    for(i=0 ;data[i] == '#'; i++){
        buf[6+i] = data[i];
    }
    buf[len+6] =buf[2]^buf[3]^buf[4]^buf[5]^buf[6];        //校驗和:數據校驗,從length到data數據的異或校驗和
//    buf[len+7] = '\0';
#if 1     //測試用
    printf("buf[0]=0x%x\n",buf[0]);
    printf("buf[1]=0x%x\n",buf[1]);
    printf("buf[2]=0x%x\n",buf[2]);
    printf("buf[3]=0x%x\n",buf[3]);
    printf("buf[4]=0x%x\n",buf[4]);
    printf("buf[5]=0x%x\n",buf[5]);
    printf("buf[6]=0x%x\n",buf[6]);
    printf("buf[7]=0x%x\n",buf[7]);
    printf("buf[8]=0x%x\n",buf[8]);
    printf("buf[9]=0x%x\n",buf[9]);
    printf("buf[10]=0x%x\n",buf[10]);
    printf("buf[11]=0x%x\n",buf[11]);
    printf("buf[len+6]=0x%x\n",(int)buf[len+6]);
#endif
}

//==============(封包,開發板)溫溼度查詢,將字符串轉換成數據包==========
void stu_to_sti_tmep(unsigned char seq,unsigned char *buf)
{
    bzero(buf,7);
    buf[0] =0xff;    //flag頭部首字節,開始標誌位固定爲0xffff
    buf[1] =0xff;    //flag頭部次字節
    buf[2] =0x00;    //length首字節,length爲協議長度:從cmd開始到正規協議結束所佔用字節數;
    buf[3] =0x04;    //length次字節
    buf[4] =0x80;    //cmd指令類型(控制/控制反饋/查詢/查詢反饋)
    buf[5] =(unsigned char)seq;        //序號,發送者給出的序號,回覆必須把序號返回發送者,以保障順序正確性。
    buf[6] =0x02;    //數據,其中data[0]爲數據類型
    buf[7] =buf[2]^buf[3]^buf[4]^buf[5]^buf[6];        //校驗和:數據校驗,從length到data數據的異或校驗和
}

#if 1
//==============(拆包,開發板)溫溼度查詢,將字符串轉換成數據包==========
void string_to_stu_tmep(struct stu_info *st,unsigned char *buf)
{
    memset(st,0,sizeof(st));
    st->flag = buf[0];        //flag頭部,開始標誌位固定爲0xffff
    if(buf[1]>0)            //判斷flag頭部高八位是否有值
        st->flag += buf[1]*256;        
    st->len = buf[2];        //length長度,length爲協議長度:從cmd開始到正規協議結束所佔用字節數;
    if(buf[3]>0)            //判斷length長度高八位是否有值
        st->len += buf[3]*256;        
    st->cmd = buf[4];    //cmd指令類型(控制/控制反饋/查詢/查詢反饋)
    st->seq = buf[5];    //序號,發送者給出的序號,回覆必須把序號返回發送者,以保障順序正確性。
    st->pac_data[0] = buf[6];
    st->pac_data[1] = buf[7];
    st->pac_data[2] = buf[8];
    st->pac_data[3] = buf[9];
    st->pac_data[4] = buf[10];
    st->pac_data[5] = buf[11];
    st->bcc = buf[12];    //校驗和:數據校驗,從length到data數據的異或校驗和
    st->pac_data[6] = '#';
}
#endif

//溫溼度
void temp_humidity_query(struct stu_info * p, cli_info * client_attr)
{
    //======不然爲客戶發送的溫溼度查詢指令,需給開發板發送指令收到命令後,反饋該客戶溫溼度值=======    
    int ret;
    int send_num;
    unsigned char send_buf[CMD_MAX_LEN];
    struct list_head *pos,*q;    //定義遍歷內核鏈表用的臨時指針    
    struct cli_info *tmp = NULL;    //定義結構體指針(包含內核鏈表成員)

    printf ("查詢函數內tmp->num =%d\n",client_attr->num);

#if 1
    /*====a)遍歷內核鏈表,查找開發板在鏈表中的位置,以便服務器給根據開發板給其發送查詢指令 =============*/
    list_for_each_safe (pos, q, client_attr->head) {
        tmp = list_entry (pos, struct cli_info, list); //client_attr指向遍歷到的某一項結構體數據
        //        if(tmp->conn_addr.sin_addr.s_addr == inet_addr(BOARD_IP)) {     //根據ip查找開發板在鏈表中的位置,send時需區其位置的fd文件描述符值
        if(tmp->num == 1) {
            printf ("***************1_查詢函數內,遍歷到開發板已經鏈接***************\n");     
            break;
        }
    }
#endif

#if 1        //send客戶傳參數錯誤??
        send_dev_board(tmp);
        
        dev_board_data.data_sequence = 0;
        unsigned char cmd_red = 0;
        cmd_red = QUERY_FEEDBACK;    //查詢反饋值
        bzero(send_buf,CMD_MAX_LEN);
        printf("1_查詢函數內dev_board_data.data_sequence= %d \n",dev_board_data.data_sequence);
        while( 1 != dev_board_data.data_sequence){
            usleep(500);
        }    //接收到開發板反饋的數據將爲1
        printf("2_查詢函數內dev_board_data.data_sequence= %d \n",dev_board_data.data_sequence);
        usleep(50000);
        printf("3_查詢函數內dev_board_data.data_sequence= %d \n",dev_board_data.data_sequence);
    list_for_each_safe (pos, q, client_attr->head) {
    tmp = list_entry (pos, struct cli_info, list); //client_attr指向遍歷到的某一項結構體數據
    //        if(tmp->conn_addr.sin_addr.s_addr == inet_addr(BOARD_IP)) {     //根據ip查找開發板在鏈表中的位置,send時需區其位置的fd文件描述符值
    if(tmp->num == 1) {
        printf ("***********2_查詢函數內,遍歷到開發板已經鏈接*************\n");     
        break;
        }
    }
        printf("函數內,發送給開發板的fd= %d \n",tmp->conn_fd);
        stu_to_sti(cmd_red,p->seq,p->pac_data,send_buf);
        ret = send (client_attr->conn_fd,send_buf,sizeof(send_buf)+7,0);     //MSG_DONTWAIT,client_attr     tmp
        if (ret < 0) {
            perror ("connect");
            exit (1);
        }else{
//            printf("%d、already send,send =%s \n",send_num,p->pac_data);
            memset(&dev_board_data ,0, sizeof(dev_board_data));        //接收成功則將開發板發送到dev_board_data.data_sequence內的結構體數據清空
        }
#else
    //=======b)send/send,發包後若沒有對方回包則繼續發包SEND_NUM次========
    for(send_num=0;send_num<B_SEND_NUM;send_num++)        //若發送SEND_NUM次後對方仍然未接收到數據則跳出(接收失敗)
    {
        send_dev_board(tmp);        

        //        usleep(B_SECOND);            //發送後、等待U_SECOND us再接收數據

        if(0 != dev_board_data.data_sequence){        //若是已經發送給開發板,且開發板已經反饋回來數據,則反饋給客戶
            unsigned char cmd_red = 0;
            cmd_red = QUERY_FEEDBACK;    //查詢反饋值
            bzero(send_buf,CMD_MAX_LEN);
            stu_to_sti(cmd_red,p->seq,p->pac_data,send_buf);

            ret = send (client_attr->conn_fd,send_buf,sizeof(send_buf)+7,0);     //MSG_DONTWAIT,client_attr     tmp
            if (ret < 0) {
                perror ("connect");
                exit (1);
            }else{
                printf("%d、already send,send =%s \n",send_num,p->pac_data);
                memset(&dev_board_data ,0, sizeof(dev_board_data));        //接收成功則將開發板發送到dev_board_data.data_sequence內的結構體數據清空
                return;        //加一個等待客戶反饋,確認接收信號會更好
            }
        }
    }    
#endif    

    printf("4_查詢函數內dev_board_data.data_sequence= %d \n",dev_board_data.data_sequence);
    printf("*******************跳出查詢函數*******************\n");
    return;
    }


    //光照強度
    void light_intensity_query(struct stu_info * p, cli_info * client_attr){
        printf("光照強度,send->buf=%s\n",p->pac_data);

        return;
    }

    //查詢
    void query_information(struct stu_info * p, cli_info * client_attr){    //怎麼發送給指定客戶,封包、裝包 見客戶端
        printf("查詢,send->buf=%s\n",p->pac_data);

        return;
    }
    //登錄驗證
    void server_check_login(struct stu_info * p, cli_info * client_attr){
        printf("登錄驗證,send->buf=%s\n",p->pac_data);

        return;
    }
    //註冊
    void register_new_client(struct stu_info * p, cli_info * client_attr){
        printf("註冊,send->buf=%s\n",p->pac_data);

        return;
    }
    //客戶退出
    void client_exit(struct stu_info * p, cli_info * client_attr){
        printf("客戶退出,send->buf=%s\n",p->pac_data);

        return;
    }

    //自動查詢
    void auto_show(struct stu_info * p, cli_info * client_attr){
        printf("客戶退出,send->buf=%s\n",p->pac_data);

        return;
    }

    //====給開發板發包(溫溼度)========
    void send_dev_board(struct cli_info * p)
    {
        state_seq = (state_seq)%255+1;            //發送序列號,可設置若相同則不接受    
        int ret =0;
        unsigned char buf[CMD_MAX_LEN];
//        printf ("##############\n,p->conn_fd =%d\n##############\n",p->conn_fd);        //?????????????????
        stu_to_sti_tmep(auto_query,buf);
        //    send_content(buf);    //打印???????????????????????????

        ret = send (p->conn_fd,buf,sizeof(buf)+7,MSG_DONTWAIT);     
        if (ret < 0) {
            perror ("connect");
            exit (1);
        }

        return ;
    }

    //===開發板反饋的包存儲到全局變量dev_board_data結構體====
    void recv_dev_board(struct stu_info * p)
    {
        time_t cur_time;
        char tbuf[20];
        struct tm *tm = NULL;
        cur_time = time (NULL);
        tm = localtime (&cur_time);
        bzero (tbuf, 20);
        sprintf (tbuf, "%4d-%02d-%02d %02d:%02d:%02d", 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,tm->tm_hour, tm->tm_min, tm->tm_sec);

        dev_board_data.data_sequence = 1;            //有新數據則設爲1
        strcpy(dev_board_data.data_time , tbuf);    //自動生成的時間
        dev_board_data.temp_value = p->pac_data[2];        //溫度值
        dev_board_data.humidity_value = p->pac_data[4];    //溼度值
        return ;
    }

    void send_content(unsigned char * keybuf)
    {
        printf("keybuf[0] 0x%x\n", keybuf[0]);
        printf("keybuf[1] 0x%x\n", keybuf[1]);
        printf("keybuf[2] 0x%x\n", keybuf[2]);
        printf("keybuf[3] 0x%x\n", keybuf[3]);
        printf("keybuf[4] 0x%x\n", keybuf[4]);
        printf("keybuf[5] 0x%x\n", keybuf[5]);
        printf("keybuf[6] 0x%x\n", keybuf[6]);
        printf("keybuf[7] 0x%x\n", keybuf[7]);
    }

    void recv_content(unsigned char * cli_buf)
    {
        printf("start_h 0: 0x%x\n", cli_buf[0]);
        printf("start_l 1 : 0x%x\n", cli_buf[1]);
        printf("lenH 2: 0x%x\n", cli_buf[2]);
        printf("lenlow 3: 0x%x\n", cli_buf[3]);
        printf("cmd 4: 0x%x\n", cli_buf[4]);
        printf("seq 5: %x\n", cli_buf[5]);
        printf("data[0] : %x\n", cli_buf[6]);
        printf("data[1] : %x\n", cli_buf[7]);
        printf("data[2] : %x\n", cli_buf[8]);
        printf("data[3] : %x\n", cli_buf[9]);
        printf("data[4] : %x\n", cli_buf[10]);
        printf("data[5] : %x\n", cli_buf[11]);
        printf("bcc 7: %x\n", cli_buf[12]);
        //    printf("當前環境溼度爲:%d,溫度爲:%d\n",cli_buf[8],cli_buf[10]);
    }
cli_data_collect.c

//======================================================sql

/***********移動互聯網數據採集系統**************

  >功能:
  >    1:項目分爲服務器、客戶端;服務器交互對象爲客戶端及WATCHER開發板
  >    2:客戶端功能:註冊、登錄、退出、刪除、查詢、控制及設置功能
  >    3:服務端功能:客戶管理、更新數據庫、數據管理排序等
  >設計關鍵詞:
  >    內核鏈表(數據保存/排序/打印)、數據庫(全部數據保存位置)、自定義協議(服務器與WATCHER板交互)、
  >    Json協議(服務器與客戶端交互)、非堵塞(超時檢測)、TCP協議、線程(新建線程實現)、心跳檢查(2分鐘)
  >WATCHER開發板智能控制協議主要指令:
  >     ①RGB燈光控制指令/RGB燈光控制反饋指令,②溫溼度查詢指令/溫溼度查詢反饋指令
  >     ③光照強度查詢指令/光照強度查詢反饋指令,④時鐘設置指令/時鐘設置反饋指令
  >     ⑤鬧鐘設置指令/ 鬧鐘設置反饋指令,⑥鬧鐘查詢指令/鬧鐘查詢反饋指令
  >
 ***********移動互聯網數據採集系統(ser)**************/
#include"data_collect.h"


/*******************************************
//==============溫溼度查詢,將字符串轉換成數據包==================
void stu_to_sti(unsigned seq,unsigned char *buf)
{
buf[0] =0xff;    //flag頭部首字節,開始標誌位固定爲0xff
buf[1] =0xff;    //flag頭部次字節
buf[2] =0x00;    //length首字節,length爲協議長度:從cmd開始到正規協議結束所佔用字節數;
buf[3] =0x04;    //length次字節
buf[4] =0x80;    //cmd指令類型(控制/控制反饋/查詢/查詢反饋)
buf[5] =(unsigned char)seq;        //序號,發送者給出的序號,回覆必須把序號返回發送者,以保障順序正確性。
buf[6] =0x02;    //數據,其中data[0]爲數據類型
}


// 填充協議: 命令會有9個本身的開銷(包含最後的'\0'字符) 
buf[0] = PACK_HEAD;            //head 

buf[1] = cmd_type;            // cmd_type 

buf[2] = 0x0;                //2字節長度,高位在前,低位在後 
buf[3] = cmd_len & 0xff;

if (cmd_len > 255) {
buf[2] = ((cmd_len & 0xff00) >> 8);
//  buf[3] = cmd_len & 0xff;
 ***********************************************/

//============(拆包,通用)將開發板上的包變成結構體======================
void string_to_stu(struct stu_info *st,unsigned char *buf)
{
    memset(st,0,sizeof(st));
    int i;
    printf("*0_******通用協議收包buf[0]=0x%x\n*********",buf[0]);
    st->flag = buf[1];        //flag頭部,開始標誌位固定爲0xffff
    if(buf[0]>0)            //判斷flag頭部高八位是否有值
        st->flag += buf[0]*256;        
    printf("*1_******通用協議收包buf[0]=0x%x\n*********",buf[0]);

    st->len = buf[3];        //length長度,length爲協議長度:從cmd開始到正規協議結束所佔用字節數;
    if(buf[2]>0)            //判斷length長度高八位是否有值
        st->len += buf[2]*256;        

    st->cmd = buf[4];    //cmd指令類型(控制/控制反饋/查詢/查詢反饋)
    st->seq = buf[5];    //序號,發送者給出的序號,回覆必須把序號返回發送者,以保障順序正確性。
//    memcpy (st->pac_data, buf+6, st->len);    //客戶/開發板數據,其中data[0]爲數據類型
    for(i=0;i < st->len; i++){
        st->pac_data[6+i] = buf[2];
    }
    st->pac_data[st->len] = '#';
    st->bcc = buf[st->len+6];    //校驗和:數據校驗,從length到data數據的異或校驗和
#if 1
    printf("*******通用協議收包buf[0]=0x%x\n*********",buf[0]);
    printf("buf[0]=0x%x\n",buf[0]);
    printf("buf[1]=0x%x\n",buf[1]);
    printf("buf[2]=0x%x\n",buf[2]);
    printf("buf[3]=0x%x\n",buf[3]);
    printf("buf[4]=0x%x\n",buf[4]);
    printf("buf[5]=0x%x\n",buf[5]);
    printf("buf[6]=0x%x\n",buf[6]);
    printf("buf[7]=0x%x\n",buf[7]);
    printf("buf[8]=0x%x\n",buf[8]);
    printf("buf[9]=0x%x\n",buf[9]);
    printf("buf[10]=0x%x\n",buf[10]);
    printf("buf[11]=0x%x\n",buf[11]);
    
    printf("buf[len+6]=0x%x\n",(int)buf[st->len+6]);
    printf("len=%d\n",st->len);        //?????????????????????????????????????
    printf("st->pac_data[0]=%c\n",st->pac_data[0]);        //?????????????????????????????????????
//    printf("拆解後的字符串=%s\n",st->pac_data);        //????????????????????    
    printf("st->bcc=%x\n",(int)st->bcc);
#endif
}

//==============(封包,通用)將字符串轉換成數據包==========
void stu_to_sti(unsigned char cmd,unsigned char seq,unsigned char *data,unsigned char *buf)
{
    int len =0;
    for(len=0;data[len] != '#'; len++);
    
    bzero(buf,len+20);
    
    printf("buf[6]=0x%x\n",buf[6]);
    printf("buf[7]=0x%x\n",buf[7]);
    printf("buf[8]=0x%x\n",buf[8]);
    printf("buf[9]=0x%x\n",buf[9]);
    printf("buf[10]=0x%x\n",buf[10]);
    printf("buf[11]=0x%x\n",buf[11]);
    
    buf[0] =0xff;    //flag頭部首字節,開始標誌位固定爲0xffff
    buf[1] =0xff;    //flag頭部次字節
    if(len > 255){
        buf[2] = len/256;
        buf[3] = len - buf[3]*256;
    }else{
        buf[2] = 0;
        buf[3] = len;        
    }
    buf[4] =cmd;    //cmd指令類型(控制/控制反饋/查詢/查詢反饋)
    buf[5] =seq;        //序號,發送者給出的序號,回覆必須把序號返回發送者,以保障順序正確性。
//    memcpy (buf+6,data,len);    //客戶/開發板數據,其中data[0]爲數據類型
    int i;
    for(i=0 ;data[i] == '#'; i++){
        buf[6+i] = data[i];
    }
    buf[len+6] =buf[2]^buf[3]^buf[4]^buf[5]^buf[6];        //校驗和:數據校驗,從length到data數據的異或校驗和
//    buf[len+7] = '\0';
#if 1     //測試用
    printf("buf[0]=0x%x\n",buf[0]);
    printf("buf[1]=0x%x\n",buf[1]);
    printf("buf[2]=0x%x\n",buf[2]);
    printf("buf[3]=0x%x\n",buf[3]);
    printf("buf[4]=0x%x\n",buf[4]);
    printf("buf[5]=0x%x\n",buf[5]);
    printf("buf[6]=0x%x\n",buf[6]);
    printf("buf[7]=0x%x\n",buf[7]);
    printf("buf[8]=0x%x\n",buf[8]);
    printf("buf[9]=0x%x\n",buf[9]);
    printf("buf[10]=0x%x\n",buf[10]);
    printf("buf[11]=0x%x\n",buf[11]);
    printf("buf[len+6]=0x%x\n",(int)buf[len+6]);
#endif
}

//==============(封包,開發板)溫溼度查詢,將字符串轉換成數據包==========
void stu_to_sti_tmep(unsigned char seq,unsigned char *buf)
{
    bzero(buf,7);
    buf[0] =0xff;    //flag頭部首字節,開始標誌位固定爲0xffff
    buf[1] =0xff;    //flag頭部次字節
    buf[2] =0x00;    //length首字節,length爲協議長度:從cmd開始到正規協議結束所佔用字節數;
    buf[3] =0x04;    //length次字節
    buf[4] =0x80;    //cmd指令類型(控制/控制反饋/查詢/查詢反饋)
    buf[5] =(unsigned char)seq;        //序號,發送者給出的序號,回覆必須把序號返回發送者,以保障順序正確性。
    buf[6] =0x02;    //數據,其中data[0]爲數據類型
    buf[7] =buf[2]^buf[3]^buf[4]^buf[5]^buf[6];        //校驗和:數據校驗,從length到data數據的異或校驗和
}

#if 1
//==============(拆包,開發板)溫溼度查詢,將字符串轉換成數據包==========
void string_to_stu_tmep(struct stu_info *st,unsigned char *buf)
{
    memset(st,0,sizeof(st));
    st->flag = buf[0];        //flag頭部,開始標誌位固定爲0xffff
    if(buf[1]>0)            //判斷flag頭部高八位是否有值
        st->flag += buf[1]*256;        
    st->len = buf[2];        //length長度,length爲協議長度:從cmd開始到正規協議結束所佔用字節數;
    if(buf[3]>0)            //判斷length長度高八位是否有值
        st->len += buf[3]*256;        
    st->cmd = buf[4];    //cmd指令類型(控制/控制反饋/查詢/查詢反饋)
    st->seq = buf[5];    //序號,發送者給出的序號,回覆必須把序號返回發送者,以保障順序正確性。
    st->pac_data[0] = buf[6];
    st->pac_data[1] = buf[7];
    st->pac_data[2] = buf[8];
    st->pac_data[3] = buf[9];
    st->pac_data[4] = buf[10];
    st->pac_data[5] = buf[11];
    st->bcc = buf[12];    //校驗和:數據校驗,從length到data數據的異或校驗和
    st->pac_data[6] = '#';
}
#endif

//溫溼度
void temp_humidity_query(struct stu_info * p, cli_info * client_attr)
{
    //======不然爲客戶發送的溫溼度查詢指令,需給開發板發送指令收到命令後,反饋該客戶溫溼度值=======    
    int ret;
    int send_num;
    unsigned char send_buf[CMD_MAX_LEN];
    struct list_head *pos,*q;    //定義遍歷內核鏈表用的臨時指針    
    struct cli_info *tmp = NULL;    //定義結構體指針(包含內核鏈表成員)

    printf ("查詢函數內tmp->num =%d\n",client_attr->num);

#if 1
    /*====a)遍歷內核鏈表,查找開發板在鏈表中的位置,以便服務器給根據開發板給其發送查詢指令 =============*/
    list_for_each_safe (pos, q, client_attr->head) {
        tmp = list_entry (pos, struct cli_info, list); //client_attr指向遍歷到的某一項結構體數據
        //        if(tmp->conn_addr.sin_addr.s_addr == inet_addr(BOARD_IP)) {     //根據ip查找開發板在鏈表中的位置,send時需區其位置的fd文件描述符值
        if(tmp->num == 1) {
            printf ("***************1_查詢函數內,遍歷到開發板已經鏈接***************\n");     
            break;
        }
    }
#endif

#if 1        //send客戶傳參數錯誤??
        send_dev_board(tmp);
        
        dev_board_data.data_sequence = 0;
        unsigned char cmd_red = 0;
        cmd_red = QUERY_FEEDBACK;    //查詢反饋值
        bzero(send_buf,CMD_MAX_LEN);
        printf("1_查詢函數內dev_board_data.data_sequence= %d \n",dev_board_data.data_sequence);
        while( 1 != dev_board_data.data_sequence){
            usleep(500);
        }    //接收到開發板反饋的數據將爲1
        printf("2_查詢函數內dev_board_data.data_sequence= %d \n",dev_board_data.data_sequence);
        usleep(50000);
        printf("3_查詢函數內dev_board_data.data_sequence= %d \n",dev_board_data.data_sequence);
    list_for_each_safe (pos, q, client_attr->head) {
    tmp = list_entry (pos, struct cli_info, list); //client_attr指向遍歷到的某一項結構體數據
    //        if(tmp->conn_addr.sin_addr.s_addr == inet_addr(BOARD_IP)) {     //根據ip查找開發板在鏈表中的位置,send時需區其位置的fd文件描述符值
    if(tmp->num == 1) {
        printf ("***********2_查詢函數內,遍歷到開發板已經鏈接*************\n");     
        break;
        }
    }
        printf("函數內,發送給開發板的fd= %d \n",tmp->conn_fd);
        stu_to_sti(cmd_red,p->seq,p->pac_data,send_buf);
        ret = send (client_attr->conn_fd,send_buf,sizeof(send_buf)+7,0);     //MSG_DONTWAIT,client_attr     tmp
        if (ret < 0) {
            perror ("connect");
            exit (1);
        }else{
//            printf("%d、already send,send =%s \n",send_num,p->pac_data);
            memset(&dev_board_data ,0, sizeof(dev_board_data));        //接收成功則將開發板發送到dev_board_data.data_sequence內的結構體數據清空
        }
#else
    //=======b)send/send,發包後若沒有對方回包則繼續發包SEND_NUM次========
    for(send_num=0;send_num<B_SEND_NUM;send_num++)        //若發送SEND_NUM次後對方仍然未接收到數據則跳出(接收失敗)
    {
        send_dev_board(tmp);        

        //        usleep(B_SECOND);            //發送後、等待U_SECOND us再接收數據

        if(0 != dev_board_data.data_sequence){        //若是已經發送給開發板,且開發板已經反饋回來數據,則反饋給客戶
            unsigned char cmd_red = 0;
            cmd_red = QUERY_FEEDBACK;    //查詢反饋值
            bzero(send_buf,CMD_MAX_LEN);
            stu_to_sti(cmd_red,p->seq,p->pac_data,send_buf);

            ret = send (client_attr->conn_fd,send_buf,sizeof(send_buf)+7,0);     //MSG_DONTWAIT,client_attr     tmp
            if (ret < 0) {
                perror ("connect");
                exit (1);
            }else{
                printf("%d、already send,send =%s \n",send_num,p->pac_data);
                memset(&dev_board_data ,0, sizeof(dev_board_data));        //接收成功則將開發板發送到dev_board_data.data_sequence內的結構體數據清空
                return;        //加一個等待客戶反饋,確認接收信號會更好
            }
        }
    }    
#endif    

    printf("4_查詢函數內dev_board_data.data_sequence= %d \n",dev_board_data.data_sequence);
    printf("*******************跳出查詢函數*******************\n");
    return;
    }


    //光照強度
    void light_intensity_query(struct stu_info * p, cli_info * client_attr){
        printf("光照強度,send->buf=%s\n",p->pac_data);

        return;
    }

    //查詢
    void query_information(struct stu_info * p, cli_info * client_attr){    //怎麼發送給指定客戶,封包、裝包 見客戶端
        printf("查詢,send->buf=%s\n",p->pac_data);

        return;
    }
    //登錄驗證
    void server_check_login(struct stu_info * p, cli_info * client_attr){
        printf("登錄驗證,send->buf=%s\n",p->pac_data);

        return;
    }
    //註冊
    void register_new_client(struct stu_info * p, cli_info * client_attr){
        printf("註冊,send->buf=%s\n",p->pac_data);

        return;
    }
    //客戶退出
    void client_exit(struct stu_info * p, cli_info * client_attr){
        printf("客戶退出,send->buf=%s\n",p->pac_data);

        return;
    }

    //自動查詢
    void auto_show(struct stu_info * p, cli_info * client_attr){
        printf("客戶退出,send->buf=%s\n",p->pac_data);

        return;
    }

    //====給開發板發包(溫溼度)========
    void send_dev_board(struct cli_info * p)
    {
        state_seq = (state_seq)%255+1;            //發送序列號,可設置若相同則不接受    
        int ret =0;
        unsigned char buf[CMD_MAX_LEN];
//        printf ("##############\n,p->conn_fd =%d\n##############\n",p->conn_fd);        //?????????????????
        stu_to_sti_tmep(auto_query,buf);
        //    send_content(buf);    //打印???????????????????????????

        ret = send (p->conn_fd,buf,sizeof(buf)+7,MSG_DONTWAIT);     
        if (ret < 0) {
            perror ("connect");
            exit (1);
        }

        return ;
    }

    //===開發板反饋的包存儲到全局變量dev_board_data結構體====
    void recv_dev_board(struct stu_info * p)
    {
        time_t cur_time;
        char tbuf[20];
        struct tm *tm = NULL;
        cur_time = time (NULL);
        tm = localtime (&cur_time);
        bzero (tbuf, 20);
        sprintf (tbuf, "%4d-%02d-%02d %02d:%02d:%02d", 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,tm->tm_hour, tm->tm_min, tm->tm_sec);

        dev_board_data.data_sequence = 1;            //有新數據則設爲1
        strcpy(dev_board_data.data_time , tbuf);    //自動生成的時間
        dev_board_data.temp_value = p->pac_data[2];        //溫度值
        dev_board_data.humidity_value = p->pac_data[4];    //溼度值
        return ;
    }

    void send_content(unsigned char * keybuf)
    {
        printf("keybuf[0] 0x%x\n", keybuf[0]);
        printf("keybuf[1] 0x%x\n", keybuf[1]);
        printf("keybuf[2] 0x%x\n", keybuf[2]);
        printf("keybuf[3] 0x%x\n", keybuf[3]);
        printf("keybuf[4] 0x%x\n", keybuf[4]);
        printf("keybuf[5] 0x%x\n", keybuf[5]);
        printf("keybuf[6] 0x%x\n", keybuf[6]);
        printf("keybuf[7] 0x%x\n", keybuf[7]);
    }

    void recv_content(unsigned char * cli_buf)
    {
        printf("start_h 0: 0x%x\n", cli_buf[0]);
        printf("start_l 1 : 0x%x\n", cli_buf[1]);
        printf("lenH 2: 0x%x\n", cli_buf[2]);
        printf("lenlow 3: 0x%x\n", cli_buf[3]);
        printf("cmd 4: 0x%x\n", cli_buf[4]);
        printf("seq 5: %x\n", cli_buf[5]);
        printf("data[0] : %x\n", cli_buf[6]);
        printf("data[1] : %x\n", cli_buf[7]);
        printf("data[2] : %x\n", cli_buf[8]);
        printf("data[3] : %x\n", cli_buf[9]);
        printf("data[4] : %x\n", cli_buf[10]);
        printf("data[5] : %x\n", cli_buf[11]);
        printf("bcc 7: %x\n", cli_buf[12]);
        //    printf("當前環境溼度爲:%d,溫度爲:%d\n",cli_buf[8],cli_buf[10]);
    }
func_data_collect.c

//======================================================數據庫

/***********移動互聯網數據採集系統**************

  >功能:
  >    1:項目分爲服務器、客戶端;服務器交互對象爲客戶端及WATCHER開發板
  >    2:客戶端功能:註冊、登錄、退出、刪除、查詢、控制及設置功能
  >    3:服務端功能:客戶管理、更新數據庫、數據管理排序等
  >設計關鍵詞:
  >    內核鏈表(數據保存/排序/打印)、數據庫(全部數據保存位置)、自定義協議(服務器與WATCHER板交互)、
  >    Json協議(服務器與客戶端交互)、非堵塞(超時檢測)、TCP協議、線程(新建線程實現)、心跳檢查(2分鐘)
  >WATCHER開發板智能控制協議主要指令:
  >     ①RGB燈光控制指令/RGB燈光控制反饋指令,②溫溼度查詢指令/溫溼度查詢反饋指令
  >     ③光照強度查詢指令/光照強度查詢反饋指令,④時鐘設置指令/時鐘設置反饋指令
  >     ⑤鬧鐘設置指令/ 鬧鐘設置反饋指令,⑥鬧鐘查詢指令/鬧鐘查詢反饋指令
  >
 ***********移動互聯網數據採集系統(ser)**************/

#ifndef __CHAT_H__
#define __CHAT_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>            /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <signal.h>
#include <pthread.h>

#include<ctype.h>                //for ispunct() and isspace()
#include <getopt.h>
#include<time.h>                //for localtime() and time()
#include<sys/stat.h>
#include<fcntl.h>
#include "list.h"


#include "list.h"
#include <pthread.h>
#define SERV_PORT  18880        // port
#define QUEUELEN   5        // 設置同一時間最多可鏈接5個客戶端
#define CMD_MAX_LEN 20        // 客戶端輸入的最大存儲內容
#define U_SECOND 700000        //客戶端發送後,等待U_SECOND us後接收數據
#define B_SECOND 50000        //板發送後
#define SEND_NUM 1             // 客戶端發送後,若U_SECOND us後沒接收到數據,再次發送數據,最大循環發送SEND_NUM次
#define B_SEND_NUM 1             // 板發送後
#define AUTO_QUERT_TIME 1    //系統自動查詢溫溼度(寫入數據庫)時間週期
#define BOARD_IP "192.168.7.100"    //開發板ip"192.168.7.100"

//========================functions================================================
#define TGB_LAMP_SET            1        //tgb燈
#define TEMP_HUMIDITY_QUERY        2        //溫溼度
#define LIGHT_INTENSITY_QUERY    3        //光照強度
#define TIME_SET                4        //時鐘設置
#define CLOCK_SET                5        //鬧鐘設置
#define CLOCK_QUERY                6        //鬧鐘查詢

#define QUERY_INFORMATION        7        //查詢
#define CONTROL_LAMPLIGHT        8        //控制
#define SET_ATTRIBUT            9        //設置
#define CLIENT_LOGIN            10        //登錄驗證
#define CLIENT_REGISTER            11        //註冊
#define CLIENT_EXIT                12        //客戶退出
#define CLIENT_DELETE            13        //客戶刪除

#define CONTROL_FEEDBACK        0x7f    //控制反饋
#define QUERY_FEEDBACK            0x8f    //查詢反饋

//========================functions====================
#define CLI_COMM_STR_LEN 25
#define CLIENT_ID    1000        // client id註冊用戶是server分配的帳號起始值id++

unsigned char state_seq;     //給開發板發送的序列號,頭文件裏面不能初始化(若不初始化有重定義清空時表示聲明)
struct data_collect dev_board_data;        //臨時存放開發板反饋的信息
unsigned int auto_query;        //自動查詢,每一個auto_query秒打印一次;
int devboard_thr_online;    //判斷自動查詢的線程是否在線

//===============保存數據庫數據(溫度、溼度、光照強度)=========
typedef struct data_collect{
    int data_sequence;        //數據序號
    char data_time[20];        //數據獲取時間
    int temp_value;                //溫度值
    int humidity_value;            //溼度值
    int intensity_value;            //光照強度值
}data_collect,*pdata_collect;

//=======client_registration(客戶註冊帳號後帳號存在數據庫中)=========
typedef struct client_registration{
    char client_name[CLI_COMM_STR_LEN];    // 帳號(在服務器的"數據庫"惟一)
    char client_passwd[CLI_COMM_STR_LEN];    //密碼
    int client_id;                //用戶ID
    int is_online;                // 在線狀態 1 在線 0 不在線
    int admin;                    //用戶權限,1爲管理員,0爲普通用戶
}_client_reg;

// ===========client attr==========================================
typedef struct    cli_info
{
    struct list_head list;        //內核鏈表(文件描述符list)
    struct list_head *head;        //內核鏈表(鏈表頭指針head)
    int num;                    //新建一個鏈表其值加1
    struct sockaddr_in conn_addr;    //保存鏈接的IP及端口號
    int conn_fd;                //accept的返回的客戶端的新的套接字描述符(鏈接時新建的線程描述符)原sockfd
    //    pthread_t tid;                //線程的描述符,unsigned long int ,printf用%lu(子線程號存儲)
    _client_reg client_reg;        //存放在數據庫中的客戶註冊信息
}cli_info;

//================函數功能的協議====================================
typedef struct 
{
    int fun_flag;                //function flag
    void (*fun)();                // function pointer variable
}proto;

//================開發板數據結構,協議要求格式=====================
typedef struct stu_info{
    unsigned short flag;    //flag頭部,開始標誌位固定爲0xffff
    unsigned short len;    //length長度,length爲協議長度:從cmd開始到正規協議結束所佔用字節數;
    unsigned char cmd;    //cmd指令類型(控制/控制反饋/查詢/查詢反饋)
    unsigned char seq;    //序號,發送者給出的序號,回覆必須把序號返回發送者,以保障順序正確性。
    unsigned char pac_data[CMD_MAX_LEN];    //數據,其中data[0]爲數據類型
    unsigned char bcc;    //校驗和:數據校驗,從length到data數據的異或校驗和
    unsigned char name[CLI_COMM_STR_LEN];    //用戶名(暱稱)
    unsigned char passwd[CLI_COMM_STR_LEN];    //密碼
}stu;

//====================debug============================
#define CHAT_DEBUG
#ifdef  CHAT_DEBUG
#define DEBUG(message...) fprintf(stderr, message)
#else
#define DEBUG(message...)
#endif

//=============fun=======server.c==========================
void *pthreads (void *arg);
void query_information(struct stu_info * p, cli_info * client_attr);
void server_check_login(struct stu_info * p, cli_info * client_attr);
void register_new_client(struct stu_info * p, cli_info * client_attr);
void client_exit(struct stu_info * p, cli_info * client_attr);
void temp_humidity_query(struct stu_info * p, cli_info * client_attr);
void light_intensity_query(struct stu_info * p, cli_info * client_attr);
void auto_show(struct stu_info * p, cli_info * client_attr);
void send_dev_board(struct cli_info * p);
void recv_dev_board(struct stu_info * p);
void *board_pthreads();
void send_content(unsigned char * keybuf);
void recv_content(unsigned char * cli_buf);
//=============fun=======拆包打包自定義協議==========================
int send_fun(unsigned char *send_buf,unsigned char seq);
int recv_fun(unsigned char *recv_buf);
void string_to_stu(struct stu_info *st,unsigned char *buf);
void stu_to_sti(unsigned char cmd,unsigned char seq,unsigned char *data,unsigned char *buf);
void string_to_stu_tmep(struct stu_info *st,unsigned char *buf);
void stu_to_sti_tmep(unsigned char seq,unsigned char *buf);

#if 0
//========數據庫涉及的函數=======保存數據庫數據(溫度、溼度、光照強度)========= 
extern sqlite3* open_data_sql(void);        

extern void creat_data_table(sqlite3 *db);
extern void init_data_table(sqlite3 *db);
extern void insert_data(sqlite3 *db, pdata_collect cli);
extern void del_data(sqlite3 *db, int inode);
extern void search_data(sqlite3 *db, int inode, pdata_collect pcli);
extern void search_last_data(sqlite3 *db, pdata_collect pcli);
extern void show_data(sqlite3 *db);
extern void close_sql(sqlite3 *db);
#endif

#endif
data_collect.h

//=====================================================express

#include"sqlite.h"

/* *************************************************數據庫函數封裝************************************************************ */


//打開數據庫文件
sqlite3* open_data_sql(void)
{    
    sqlite3 *db;
    sqlite3_open("./data_collect.db", &db);
    return db;
}        


//建立表
void creat_data_table(sqlite3 *db)
{
    int ret;
    char *errmsg;
    char sql[SQL_SIZE] = {'\0'};

    sprintf(sql, "create table data_collect_table(data_sequence int, data_time char(20), temp_value int, humidity_value int, intensity_value int)");
    ret = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
    if(SQLITE_OK != ret)
    {
        printf("create:%s\n", errmsg);
    }
}


//初始化表
void init_data_table(sqlite3 *db)
{
    int ret;
    char *errmsg;
    char sql[SQL_SIZE] = {'\0'};

    sprintf(sql, "insert into data_collect_table(data_sequence, data_time , temp_value, humidity_value, intensity_value) values(1, '--分隔行--', 0, 0, 0)");
    ret = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
    if(SQLITE_OK != ret)
    {
        printf("insert:%s\n", errmsg);
        exit(0);
    }
}


//根據序號(inode)刪除某組數據
void del_data(sqlite3 *db, int inode)
{
    int ret = -1;
    char *errmsg;
    char sql[SQL_SIZE] = {'\0'};
    
    sprintf(sql, "delete from data_collect_table where data_sequence=%d", inode);
    ret = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
    if(SQLITE_OK != ret)
    {
        printf("delete:%s\n", errmsg);        
    }
}


//根據序號(inode)讀取某組數據,並存儲到plic指向的結構體
void search_data(sqlite3 *db, int inode, pdata_collect pcli)
{
    int i;
    int ret;
    char *errmsg;
    char **result;
    int nrow = -1;
    int ncolumn = -1;
//    char *t_name="data_collect_table";
    char sql[SQL_SIZE] = {'\0'};
    int  sum0 = 5, sum1 = 6, sum2 = 7, sum3 = 8, sum4 = 9;
    
    //查詢client表某個帳號相關的信息
    //select * from table_name where [expression]
    sprintf(sql, "select * from data_collect_table where data_sequence=%d", inode);
    ret = sqlite3_get_table(db, sql, &result, &nrow, &ncolumn, &errmsg);
    if(SQLITE_OK != ret)
    {
        printf("search:%s\n", errmsg);        
    }
    
    //提取數據到結構體
    for(i=0; i<(nrow+1)*ncolumn; i++)
    {
        if(i < 5)
        {        
            continue;    
        }
        if(i == sum0)
        {
            pcli->data_sequence = atoi(result[i]);            
            continue;
        }
        if(i == sum1)
        {
            memcpy(pcli->data_time, result[i], 19);
            continue;
        }
        if(i == sum2)
        {
            pcli->temp_value = atoi(result[i]);
            continue;
        }
        if(i == sum3)
        {
            pcli->humidity_value = atoi(result[i]);
            continue;
        }
        if(i == sum4)
        {
            pcli->intensity_value = atoi(result[i]);
            continue;
        }    
    }
    printf("\n");
    
}


//讀取最近一次存儲的數據,並存儲到plic指向的結構體(待解決:該作法採用降序輸出所有數據,只取第一行數據,效率較低; 會隨着數據的增多而減慢運行速度)
void search_last_data(sqlite3 *db, pdata_collect pcli)
{
    int i;
    int ret;
    char *errmsg;
    char **result;
    int nrow = -1;
    int ncolumn = -1;
//    char *t_name="data_collect_table";
    char sql[SQL_SIZE] = {'\0'};
    int  sum0 = 5, sum1 = 6, sum2 = 7, sum3 = 8, sum4 = 9;
    
    //查詢client表某個帳號相關的信息
    //select * from table_name where [expression]
    sprintf(sql, "select * from data_collect_table order by data_sequence desc");
    ret = sqlite3_get_table(db, sql, &result, &nrow, &ncolumn, &errmsg);
    if(SQLITE_OK != ret)
    {
        printf("search:%s\n", errmsg);        
    }
    
    //提取數據到結構體
    for(i=0; i<(nrow+1)*ncolumn; i++)
    {
        if(i < 5)
        {        
            continue;    
        }
        if(i == sum0)
        {
            pcli->data_sequence = atoi(result[i]);
            continue;
        }
        if(i == sum1)
        {
            memcpy(pcli->data_time, result[i], 19);
            continue;
        }
        if(i == sum2)
        {
            pcli->temp_value = atoi(result[i]);
            continue;
        }
        if(i == sum3)
        {
            pcli->humidity_value = atoi(result[i]);
            continue;
        }
        if(i == sum4)
        {
            pcli->intensity_value = atoi(result[i]);
            continue;
        }    
    }
    printf("\n");
    
}


//插入1組數據
void insert_data(sqlite3 *db, pdata_collect cli)
{    
    int count;
    int ret = -1;
    char *errmsg;
    char sql[SQL_SIZE] = {'\0'};
    
    char buf[20];
    time_t cur_time;
    
    pdata_collect client_tmp;
    client_tmp = (pdata_collect)malloc(sizeof(data_collect));
    //更改序號data_sequence
    search_last_data(db, client_tmp);
    //printf("%d\t%s\t%d\t%d\t%d\n",client_tmp->data_sequence, client_tmp->data_time, client_tmp->temp_value, client_tmp->humidity_value, client_tmp->intensity_value);        
    count = client_tmp->data_sequence;
    count++;
    free(client_tmp);

    
    cli->data_sequence = count;
    
    struct tm *tm = NULL;
    cur_time = time(NULL); /*返回從1970-01-01 00:00:00(格林威治標準時間)到如今的秒數 */
      
    tm = localtime(&cur_time);
     
    bzero(buf,20);
    sprintf(buf,"%4d-%02d-%02d %02d:%02d:%02d",1900+tm->tm_year, tm->tm_mon+1, tm->tm_mday, tm->tm_hour,tm->tm_min,tm->tm_sec);
    memcpy(cli->data_time, buf, 19);            
        
    sprintf(sql, "insert into data_collect_table(data_sequence, data_time , temp_value, humidity_value, intensity_value) values(%d, '%s', %d, %d, %d)", cli->data_sequence, cli->data_time, cli->temp_value, cli->humidity_value, cli->intensity_value);
    ret = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
    if(SQLITE_OK != ret)
    {
        printf("insert:%s\n", errmsg);
        exit(0);
    }
    
    count++;   //與    if(count != 1)配合,使第一次數據存儲正常
}


//打印數據
void show_data(sqlite3 *db)
{
    int i;
    int ret;
    char *errmsg;
    char **result;
    int nrow = -1;
    int ncolumn = -1;
    char *t_name="data_collect_table";
    char sql[SQL_SIZE] = {'\0'};
    //查詢client表全部信息
    sprintf(sql, "select * from %s", t_name);
    ret = sqlite3_get_table(db, sql, &result, &nrow, &ncolumn, &errmsg);

    //打印查詢結果
    for(i=0; i<(nrow+1)*ncolumn; i++){
        if(i%5 == 0)
            printf("\n");
        printf("%s\t", result[i]);
    }
    printf("\n");
}


//關閉數據庫
void close_sql(sqlite3 *db)
{
    sqlite3_close(db);
}


/* ******************************************************************************************************************************* */
sqlite.c

//=====================================================數組

#ifndef __LIST_H
#define __LIST_H

/* This file is from Linux Kernel (include/linux/list.h)
* and modified by simply removing hardware prefetching of list items.
* Here by copyright, credits attributed to wherever they belong.
* Kulesh Shanmugasundaram (kulesh [squiggly] isis.poly.edu)
*/

/*
* Simple doubly linked list implementation.
*
* Some of the internal functions (「__xxx」) are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/

/**
 * container_of - cast a member of a structure out to the containing structure
 *
 * @ptr:    the pointer to the member.
 * @type:    the type of the container struct this is embedded in.
 * @member:    the name of the member within the struct.
 *
 */
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

#define container_of(ptr, type, member) ({            \
        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
        (type *)( (char *)__mptr - offsetof(type,member) );})

/*
 * These are non-NULL pointers that will result in page faults
 * under normal circumstances, used to verify that nobody uses
 * non-initialized list entries.
 */
#define LIST_POISON1  ((void *) 0x00100100)
#define LIST_POISON2  ((void *) 0x00200

struct list_head
{
    struct list_head *next, *prev;
};

#define LIST_HEAD_INIT(name) { &(name), &(name) }

#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)

#define INIT_LIST_HEAD(ptr) do { \
    (ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)

/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add (struct list_head *new, struct list_head *prev, struct list_head *next)
{
    next->prev = new;
    new->next = next;
    new->prev = prev;
    prev->next = new;
}

/**
* list_add – add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void list_add (struct list_head *new, struct list_head *head)
{
    __list_add (new, head, head->next);
}

/**
* list_add_tail – add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail (struct list_head *new, struct list_head *head)
{
    __list_add (new, head->prev, head);
}

/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del (struct list_head *prev, struct list_head *next)
{
    next->prev = prev;
    prev->next = next;
}

/**
* list_del – deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is in an undefined state.
*/
static inline void list_del (struct list_head *entry)
{
    __list_del (entry->prev, entry->next);
    entry->next = (void *) 0;
    entry->prev = (void *) 0;
}

/**
* list_del_init – deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static inline void list_del_init (struct list_head *entry)
{
    __list_del (entry->prev, entry->next);
    INIT_LIST_HEAD (entry);
}

/**
* list_move – delete from one list and add as another’s head
* @list: the entry to move
* @head: the head that will precede our entry
*/
static inline void list_move (struct list_head *list, struct list_head *head)
{
    __list_del (list->prev, list->next);
    list_add (list, head);
}

/**
* list_move_tail – delete from one list and add as another’s tail
* @list: the entry to move
* @head: the head that will follow our entry
*/
static inline void list_move_tail (struct list_head *list, struct list_head *head)
{
    __list_del (list->prev, list->next);
    list_add_tail (list, head);
}

/**
* list_empty – tests whether a list is empty
* @head: the list to test.
*/
static inline int list_empty (struct list_head *head)
{
    return head->next == head;
}

static inline void __list_splice (struct list_head *list, struct list_head *head)
{
    struct list_head *first = list->next;
    struct list_head *last = list->prev;
    struct list_head *at = head->next;

    first->prev = head;
    head->next = first;

    last->next = at;
    at->prev = last;
}

/**
* list_splice – join two lists
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static inline void list_splice (struct list_head *list, struct list_head *head)
{
    if (!list_empty (list))
        __list_splice (list, head);
}

/**
* list_splice_init – join two lists and reinitialise the emptied list.
* @list: the new list to add.
* @head: the place to add it in the first list.
*
* The list at @list is reinitialised
*/
static inline void list_splice_init (struct list_head *list, struct list_head *head)
{
    if (!list_empty (list)) {
        __list_splice (list, head);
        INIT_LIST_HEAD (list);
    }
}

/**
* list_entry – get the struct for this entry
* @ptr:    the &struct list_head pointer.
* @type:    the type of the struct this is embedded in.
* @member:    the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

/**
* list_for_each    -    iterate over a list
* @pos:    the &struct list_head to use as a loop counter.
* @head:    the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); \
pos = pos->next)

/**
* list_for_each_prev    -    iterate over a list backwards
* @pos:    the &struct list_head to use as a loop counter.
* @head:    the head for your list.
*/
#define list_for_each_prev(pos, head) \
for (pos = (head)->prev; pos != (head); \
pos = pos->prev)

/**
* list_for_each_safe    -    iterate over a list safe against removal of list entry
* @pos:    the &struct list_head to use as a loop counter.
* @n:        another &struct list_head to use as temporary storage
* @head:    the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)

/**
* list_for_each_entry    -    iterate over list of given type
* @pos:    the type * to use as a loop counter.
* @head:    the head for your list.
* @member:    the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member)                \
for (pos = list_entry((head)->next, typeof(*pos), member);    \
&pos->member != (head);                     \
pos = list_entry(pos->member.next, typeof(*pos), member))

/**
* list_for_each_entry_safe – iterate over list of given type safe against removal of list entry
* @pos:    the type * to use as a loop counter.
* @n:        another type * to use as temporary storage
* @head:    the head for your list.
* @member:    the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member)            \
for (pos = list_entry((head)->next, typeof(*pos), member),    \
n = list_entry(pos->member.next, typeof(*pos), member);    \
&pos->member != (head);                     \
pos = n, n = list_entry(n->member.next, typeof(*n), member))

#endif
list.h

//=====================================================服務器

CC = gcc
CFLAGS = -Wall -g -O
OBJS = sev_data_collect cli_data_collect
all : $(OBJS)

sev_data_collect : sev_data_collect.c func_data_collect.c 
    $(CC) $(CFLAGS) -o $@ $^ -lpthread
cli_data_collect : cli_data_collect.c func_data_collect.c
    $(CC) $(CFLAGS) -o $@ $^ -lpthread
clean :
    $(RM) $(OBJS) *.o
    
makefile
相關文章
相關標籤/搜索