问题:客户端对应的服务端如何设计?TCP通信框架设计服务端负责监听连接状态Connect:生成通信客户端(TcpClient),并给出事件通知Close:给出事件通知,并销毁客户端负责监听数据通信状态,并给出事件通知服务器事件设计EVT_CONN:客户端连接服务器时触发,创建TcpClient进行通信EVT_DATA:客户端数据到达服务器时触发,使用TcpClient读取数据EVT_CLOSE:客户端断开服务时触发,相关TcpClient将被销毁。问题:服务器如何知道何时通知事件回调?服务端通过select机制触发事件回调!服务器接口设计typedefvoidTcpServer;typedefvoid(*Listener)(TcpClient*,int);enum{EVT_CONN,EVT_DATA,EVT_CLOSE};TcpServer*TcpServer_New();intTcpServer_Start(TcpServer*server,intport,intmax);voidTcpServer_Stop(TcpServer*server);voidTcpServer_SetListener(TcpServer*server,Listenerlistener);intTcpServer_IsValid(TcpServer*server);voidTcpServer_DoWork(TcpServer*server);voidTcpServer_Del(TcpServer*server);服务器关键代码实现——初始化typedefstructtcp_server{intfd;有效;听众cb;TcpClient*client[FD_SIZE];}Server;TcpServer*TcpServer_New(){Server*ret=malloc(sizeof(Server));如果(ret){inti=0;ret->fd=-1;ret->有效=0;ret->cb=NULL;}returnret;}服务器关键代码实现——事件监听FD_ZERO(&reads);FD_SET(s->fd,&reads);最大值=s->fd;while(s->valid){rset=读取;timeout.tv_sec=0;timeout.tv_usec=5000;num=select(max+1,&rset,0,0,&timeout);如果(num>0){max=SelectHandler(s,&rset,&reads,num,mac);}}服务器关键代码实现-连接事件和数据事件if(index==s->fd){//连接事件structsockaddr_incaddr={0};socklen_tasize=sizeof(caddr);index=accept(s->fd,(structsockaddr*)&addr,&asize);如果(索引>-1){FD_SET(索引,读取);ret=(索引>最大值)?索引:最大值;s->client[index]=TcpClient_From(index);事件=EVT_CONN;}}else{//数据事件event=EVT_DATA;}服务器关键代码实现-断开事件&事件通知if(s->cb){if(TcpClient_IsValid(s->client[index])){s->cb(s->客户端[ind例如],事件);//EVT_CONN&EVT_DATA事件通信}else{if(s->client[index]){s->cb(s->client[index],EVT_CLOSE);//断连事件通知TcpClient_Del(s->client[index]);s->客户端[索引]=NULL;FD_CLR(索引,读取);}}}编写程序实验tcp_server.h#ifndefTCP_SERVER_H#defineTCP_SERVER_H#include"tcp_client.h"typedefvoidTcpServer;typedefvoid(*Listener)(TcpClient*,int);enum{EVT_CONN,EVT_DATA,EVT_CLOSE};TcpServer*TcpServer_New();intTcpServer_Start(TcpServer*server,intport,intmax);voidTcpServer_Stop(TcpServer*server);voidTcpServer_SetListener(TcpServer*server,Listenerlistener);intTcpServer_IsValid(TcpServer*server);voidTcpServer_DoWork(TcpServer*server);voidTcpServer_Del(TcpServer*server);#endiftcp_server.c#include"tcp_server.h"#include"tcp_client.h"#include#include#include#include#include#include#include#include#defineFD_SIZE1024typedefstructtcp_server{intfd;有效;听众cb;TcpClient*client[FD_SIZE];}Server;TcpServer*TcpServer_New(){Server*ret=malloc(sizeof(Server));如果(ret){inti=0;ret->fd=-1;ret->有效=0;ret->cb=NULL;for(i=0;iclient[i]=NULL;}}returnret;}intTcpServer_Start(TcpServer*server,intport,intmax){Server*s=(Server*)server;if(s&&!s->valid){structsockaddr_insaddr={0};s->fd=socket(PF_INET,SOCK_STREAM,0);s->有效=(s->fd!=-1);saddr.sin_family=AF_INET;saddr.sin_addr.s_addr=htonl(INADDR_ANY);saddr.sin_port=htons(端口);s->valid=s->valid&&(bind(s->fd,(structsockaddr*)&saddr,sizeof(saddr))!=-1);s->valid=s->valid&&(listen(s->fd,max)!=-1);}returns->valid;}voidTcpServer_Stop(TcpServer*server){Server*s=(Server*)server;如果(s){inti=0;s->有效=0;关闭(s->fd);for(i=0;iclient[i]);s->client[i]=NULL;}}}voidTcpServer_SetListener(TcpServer*server,Listenerlistener){Server*s=(Server*)server;如果(s){s->cb=侦听器;}}intTcpServer_IsValid(TcpServer*server){返回服务器?((Server*)server)->valid:0;}staticintSelectHandler(Server*s,fd_set*rset,fd_set*reads,intnum,intmax){intret=max;诠释我=0;对于(i=0;i<=max;++i){if(FD_ISSET(i,rset)){intindex=i;内部事件=-1;if(index==s->fd){structsockaddr_incaddr={0};socklen_tasize=sizeof(structsockaddr_in);index=accept(s->fd,(structsockaddr*)&caddr,&asize);如果(索引>-1){FD_SET(索引,读取);ret=(index>max)?索引:最大值;s->client[index]=TcpClient_From(index);事件=EVT_CONN;}}else{事件=EVT_DATA;}if(s->cb){if(TcpClient_IsValid(s->client[index])){s->cb(s->client[index],event);}else{if(s->client[index]){s->cb(s->client[index],EVT_CLOSE);}TcpClient_Del(s->client[index]);s->客户端[独立x]=NULL;FD_CLR(索引,读取);}}}}returnret;}voidTcpServer_DoWork(TcpServer*server){Server*s=(Server*)server;如果(s&&s->有效){intmax=0;整数=0;fd_set读取={0};fd_setrset={0};结构timeval超时={0};FD_ZERO(&读取);FD_SET(s->fd,&reads);最大值=s->fd;while(s->valid){rset=读取;timeout.tv_sec=0;timeout.tv_usec=10000;num=select(max+1,&rset,0,0,&timeout);如果(num>0){max=SelectHandler(s,&rset,&reads,num,max);}}}}voidTcpServer_Del(TcpServer*server){TcpServer_Stop(server);free(server);}测试:server.c#include#include#include#include"tcp_server.h"voidEventListener(TcpClient*client,intevt){if(evt==EVT_CONN){printf("Connect:%p\n",client);}elseif(evt==EVT_DATA){Message*m=TcpClient_RecvMsg(client);如果(m){char*s=TcpClient_GetDate(客户端);如果(m->index==0){s=malloc(m->total+1);TcpClient_SetData(客户端,s);}strcpy(s+m->index,m->payload);if((m->index+1)==m->total){printf("数据:%s\n",s);免费;}免费(米);}}elseif(evt==EVT_CLOSE){printf("close:%p\n",client);}}intmain(){TcpServer*server=TcpServer_New();如果(服务器){intr=TcpServer_Start(服务器,8888,20);如果(r){TcpServer_SetListener(服务器,EventListener);TcpServer_DoWork(服务器);}}返回0;}输出:连接:0x5602eb035690数据:D.T.Softwareclose:0x5602eb035690