移*动互*联网数*据采*集系*统

 

//======================================================

/***********移动互联网数据采集系统**************
  >功能:
  >    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");

    //=====5、初始化内核链,设置链表、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、端口及一定填充区域

    /*=====6、循环,内核链表对所有连接客户端的结构体进行连接,
      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

//======================================================

/***********移动互联网数据采集系统**************
  >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

//======================================================

/***********移动互联网数据采集系统**************

  >功能:
  >    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

//=====================================================

#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

 

posted @ 2017-11-21 01:09  chengj001  阅读(202)  评论(0)    收藏  举报