user-0 提问: C 实现HTML5服务时，遇到握手状态的判断问题...

回复:
user: user-0
content: 引用 5 楼 user-1 的回复:题外话: 看看 RecvData 这个函数 每当 socket  可读时就触发一次, 每次都要判断一次  "握手了没有呀"...  "握手了没有呀" ...  用 FSM 的方式就可以 减少一次 if , 还可以务业分离，把 握手 业务抽出来， 而且 H5的握手协议 是很很多版本  － －!!!   // ===================================== 好久没碰过 epoll 了.... 楼主可以试试 libevent 或  libev   早上试试了， 直接在结构体了加 一个状态变量，可以的，多个客户端连接没有问题。通信都正常也...  你的建议非常好，看你的描述，应该是FSM更好，更合理。 但是你第一回复，没懂... 也不好意思老麻烦你

user: user-0
content: 引用 5 楼 user-1 的回复:题外话: 看看 RecvData 这个函数 每当 socket  可读时就触发一次, 每次都要判断一次  "握手了没有呀"...  "握手了没有呀" ...  用 FSM 的方式就可以 减少一次 if , 还可以务业分离，把 握手 业务抽出来， 而且 H5的握手协议 是很很多版本  － －!!!   // ===================================== 好久没碰过 epoll 了.... 楼主可以试试 libevent 或  libev  谢谢你呀  俺有空去了解一下libevent  ，，，  如果按照您4楼的方法在 设置一个状态，，那在发送函数里，会不会改变这个值的状态呢？ 按你方法先试试，有问题再请教    // send data   void SendData(int fd, int events, void *arg)   {       struct myevent_s *ev = (struct myevent_s*)arg;       int len,i;       // send data       len = send(fd, ev->buff + ev->s_offset, ev->len - ev->s_offset, 0);     if(len > 0)     {         //printf("send[fd=%d], [%d<->%d]%s\n", fd, len, ev->len, ev->buff);         printf("send data is :\n");         for(i=0;i<ev->buff[1]+2;i++)                 printf("  %02X", ev->buff[i]);          printf("\n");         ev->s_offset += len;         if(ev->s_offset == ev->len)         {             // change to receive event             EventDel(g_epollFd, ev);             EventSet(ev, fd, RecvData, ev);               EventAdd(g_epollFd, EPOLLIN, ev);           }   //这三个函数都操作到了EV这个结构提，而状态都会经过这三个函数走一圈     }     else       {           close(ev->fd);           EventDel(g_epollFd, ev);           printf("send[fd=%d] error[%d]\n", fd, errno);       }   }

user: user-1
content: 题外话: 看看 RecvData 这个函数 每当 socket  可读时就触发一次, 每次都要判断一次  "握手了没有呀"...  "握手了没有呀" ...  用 FSM 的方式就可以 减少一次 if , 还可以务业分离，把 握手 业务抽出来， 而且 H5的握手协议 是很很多版本  － －!!!   // ===================================== 好久没碰过 epoll 了.... 楼主可以试试 libevent 或  libev

user: user-1
content: 引用 1 楼 wanyeye 的回复:相对全一点的代码，代码都是来自网络，目前这样方式，只能接受一个客户端连接，并交互通信。  如何在客户端建立连接时，为每个客户端，标记一个状态，如果是第一次连接，则标记一个状态，以便完成握手动作， 握手后，修改状态，直到该客户端关闭连接再恢复该状态，，方便该客户端下次连接服务器以完成握手。  ......  每一个客户端都是一个 struct myevent_s ，如果用状态标记这种方式可以向里面添加  struct myevent_s   {       int fd;       void (*call_back)(int fd, int events, void *arg);       int events;       void *arg;       int status; // 1: in epoll wait list, 0 not in       unsigned char buff[1024]; // recv data buffer       int len, s_offset;       long last_active; // last active time     int connected;    //添加这个标记-- 0:未握手.1:完成握手. };    // //  然后修改 // void RecvData(int fd, int events, void *arg)   {     // ..    // ..   // ..   // if((0==connected))/目前只能接受一个客户端的连接握手，当第二个.......    if((0 == ev->connected))  ///     {                              printf(" shakehand is ok %d \n",fd);                 // ...              secWebSocketKey=computeAcceptKey(ev->buff);                shakeHand(fd,secWebSocketKey);                // connected=1;     // ==========> 相应的 connected 都改成 ev->connected;             ev->connected=1;             // ....     } }

user: user-0
content: 引用 2 楼 user-1 的回复:觉得做个类 FSM 的操作 会方便点 添加一个 握手状态处理 void hand_shake(int fd, int evs, void *arg) {    /// 握手处理完成后   // 改变 call_back;   // EventSet( ...) 域直接   ((struct myevent_s *) arg)->call_back = RecvData;   return 0; }  // 修改接受 客户端connect函数 void AcceptConn(int fd, int events, void *arg)   {      // add a read event for receive data        //   EventSet(&g_Events[i], nfd, RecvData, &g_Events[i]);      // 把原来的 RecvData 改成 hand_shake    EventSet(&g_Events[i], nfd, hand_shake, &g_Events[i]);  }   // ====================================== 把 myevent_s 中的 call_back 变成  call_backs 这种方法会更完整点  调用:  ev->call_back[ev->status](ev->fd, events[i].events, ev->arg);   这样改变 status 就改变了 call_back   没看懂。。。

user: user-1
content: 觉得做个类 FSM 的操作 会方便点 添加一个 握手状态处理 void hand_shake(int fd, int evs, void *arg) {    /// 握手处理完成后   // 改变 call_back;   // EventSet( ...) 域直接   ((struct myevent_s *) arg)->call_back = RecvData;   return 0; }  // 修改接受 客户端connect函数 void AcceptConn(int fd, int events, void *arg)   {      // add a read event for receive data        //   EventSet(&g_Events[i], nfd, RecvData, &g_Events[i]);      // 把原来的 RecvData 改成 hand_shake    EventSet(&g_Events[i], nfd, hand_shake, &g_Events[i]);  }   // ====================================== 把 myevent_s 中的 call_back 变成  call_backs 这种方法会更完整点  调用:  ev->call_back[ev->status](ev->fd, events[i].events, ev->arg);   这样改变 status 就改变了 call_back

user: user-0
content: 相对全一点的代码，代码都是来自网络，目前这样方式，只能接受一个客户端连接，并交互通信。  如何在客户端建立连接时，为每个客户端，标记一个状态，如果是第一次连接，则标记一个状态，以便完成握手动作， 握手后，修改状态，直到该客户端关闭连接再恢复该状态，，方便该客户端下次连接服务器以完成握手。     #define REQUEST_LEN_MAX 1024 #define DEFEULT_SERVER_PORT 8000 #define WEB_SOCKET_KEY_LEN_MAX 256 #define RESPONSE_HEADER_LEN_MAX 1024 #define LINE_MAX 256 #define HOST_IP_ADDRESS_TCP "192.168.34.52" #define MAX_EVENTS 500   #define HOST_PORT_TCP 4530  int connected=0;//0:not connect.1:connected.  struct myevent_s   {       int fd;       void (*call_back)(int fd, int events, void *arg);       int events;       void *arg;       int status; // 1: in epoll wait list, 0 not in       unsigned char buff[1024]; // recv data buffer       int len, s_offset;       long last_active; // last active time };   // set event   void EventSet(struct myevent_s *ev, int fd, void (*call_back)(int, int, void*), void *arg)   {       ev->fd = fd;       ev->call_back = call_back;       ev->events = 0;       ev->arg = arg;      ev->status = 0;     bzero(ev->buff, sizeof(ev->buff));     ev->s_offset = 0;       ev->len = 0;     ev->last_active = time(NULL);   }   // add/mod an event to epoll   void EventAdd(int epollFd, int events, struct myevent_s *ev)   {       struct epoll_event epv = {0, {0}};       int op;       epv.data.ptr = ev;       epv.events = ev->events = events;       if(ev->status == 1){           op = EPOLL_CTL_MOD;       }       else{         op = EPOLL_CTL_ADD;           ev->status = 1;      }       if(epoll_ctl(epollFd, op, ev->fd, &epv) < 0)           printf("Event Add failed[fd=%d], evnets[%d]\n", ev->fd, events);       else           printf("Event Add OK[fd=%d], op=%d, evnets[%0X], status:[%d]\n", ev->fd, op, events, ev->status);   }   // delete an event from epoll   void EventDel(int epollFd, struct myevent_s *ev)   {       struct epoll_event epv = {0, {0}};       if(ev->status != 1) return;       epv.data.ptr = ev;       ev->status = 0;     epoll_ctl(epollFd, EPOLL_CTL_DEL, ev->fd, &epv);   }   int g_epollFd;   struct myevent_s g_Events[MAX_EVENTS+1]; // g_Events[MAX_EVENTS] is used by listen fd   void RecvData(int fd, int events, void *arg);   void SendData(int fd, int events, void *arg);    // accept new connections from clients   void AcceptConn(int fd, int events, void *arg)   {       struct sockaddr_in sin;       socklen_t len = sizeof(struct sockaddr_in);       int nfd, i;       // accept       if((nfd = accept(fd, (struct sockaddr*)&sin, &len)) == -1)       {           if(errno != EAGAIN && errno != EINTR)           {           }         printf("%s: accept, %d", __func__, errno);           return;       }       do       {           for(i = 0; i < MAX_EVENTS; i++)           {               if(g_Events[i].status == 0)               {                   break;               }           }           if(i == MAX_EVENTS)           {               printf("%s:max connection limit[%d].", __func__, MAX_EVENTS);               break;           }           // set nonblocking         int iret = 0;         if((iret = fcntl(nfd, F_SETFL, O_NONBLOCK)) < 0)         {             printf("%s: fcntl nonblocking failed:%d", __func__, iret);             break;         }         // add a read event for receive data           EventSet(&g_Events[i], nfd, RecvData, &g_Events[i]);           EventAdd(g_epollFd, EPOLLIN, &g_Events[i]);      }while(0);            printf("new conn %s, %d,time:%ld, pos:%d \n", inet_ntoa(sin.sin_addr),              ntohs(sin.sin_port), g_Events[i].last_active, i);  }   // receive data   // 帖子内容大小有限制，放主贴里了  // send data   void SendData(int fd, int events, void *arg)   {       struct myevent_s *ev = (struct myevent_s*)arg;       int len,i;       // send data       len = send(fd, ev->buff + ev->s_offset, ev->len - ev->s_offset, 0);     if(len > 0)     {         //printf("send[fd=%d], [%d<->%d]%s\n", fd, len, ev->len, ev->buff);         printf("send data is :\n");         for(i=0;i<ev->buff[1]+2;i++)                 printf("  %02X", ev->buff[i]);          printf("\n");         ev->s_offset += len;         if(ev->s_offset == ev->len)         {             // change to receive event             EventDel(g_epollFd, ev);             EventSet(ev, fd, RecvData, ev);               EventAdd(g_epollFd, EPOLLIN, ev);           }     }     else       {           close(ev->fd);           EventDel(g_epollFd, ev);           printf("send[fd=%d] error[%d]\n", fd, errno);       }   }    void InitListenSocket(int epollFd, short port,char* ip)   {       int listenFd = socket(AF_INET, SOCK_STREAM, 0);       fcntl(listenFd, F_SETFL, O_NONBLOCK); // set non-blocking       printf("server listen fd=%d\n", listenFd);       EventSet(&g_Events[MAX_EVENTS], listenFd, AcceptConn, &g_Events[MAX_EVENTS]);       // add listen socket       EventAdd(epollFd, EPOLLIN, &g_Events[MAX_EVENTS]);       // bind & listen       struct sockaddr_in sin;       bzero(&sin, sizeof(sin));       sin.sin_family = AF_INET;       //sin.sin_addr.s_addr = INADDR_ANY;       //sin.sin_addr.s_addr = inet_addr(HOST_IP_ADDRESS_TCP);     sin.sin_addr.s_addr = inet_addr(ip);     sin.sin_port = htons(port);       bind(listenFd, (struct sockaddr*)&sin, sizeof(sin));       listen(listenFd, 5);     printf("server ip is : %s \n",ip); }    int main(int argc, char *argv[]) {         struct sockaddr_in servaddr, cliaddr;         socklen_t cliaddr_len;         int listenfd, connfd;         char buf[REQUEST_LEN_MAX];         char *data;         char str[INET_ADDRSTRLEN];         char *secWebSocketKey;         int i,n;         //int connected=0;//0:not connect.1:connected.                  int port= DEFEULT_SERVER_PORT;          if(argc>1)           {             port=atoi(argv[1]);           }         if(port<=0||port>0xFFFF)           {             printf("Port(%d) is out of range(1-%d)\n",port,0xFFFF);             return;           }           // create epoll ///////////////////////      g_epollFd = epoll_create(MAX_EVENTS);       if(g_epollFd <= 0) printf("create epoll failed.%d\n", g_epollFd);       // create & bind listen socket, and add to epoll, set non-blocking       InitListenSocket(g_epollFd, HOST_PORT_TCP,HOST_IP_ADDRESS_TCP);     // event loop       struct epoll_event events[MAX_EVENTS];       printf("server running:port[%d]\n", HOST_PORT_TCP);       int checkPos = 0;            /////////////////////////////////                   while (1)           {                                      // wait for events to happen           int fds = epoll_wait(g_epollFd, events, MAX_EVENTS, 1000);           if(fds < 0){             printf("epoll_wait error, exit\n");               break;           }        for( i = 0; i < fds; i++){                    struct myevent_s *ev = (struct myevent_s*)events[i].data.ptr;               if((events[i].events&EPOLLIN)&&(ev->events&EPOLLIN)) // read event               {                   ev->call_back(ev->fd, events[i].events, ev->arg);               }               if((events[i].events&EPOLLOUT)&&(ev->events&EPOLLOUT)) // write event               {                   ev->call_back(ev->fd, events[i].events, ev->arg);               }           }                         }//while         close(connfd); }