问:如何将之前的通信框架扩展为支持UDP通信,进而成为一个完整的网络通信框架?UDP通信扩展UDP通信实体概要设计每个UDPPoint地位平等(因为不需要主动发起连接),可以通过ip地址和端口号进行通信UDPPoint数据发送和接收单位为:Message或ByteIn接收端口的设计,同TcpClientConsistency(框架接口一致性)目标:封装nativesocket细节,关注UDP通信逻辑UDP通信实体接口设计typedefvoidUdpPoint;UdpPoint*UdpPoint_New(intport);UdpPoint*UdpPoint_From(intfd);voidUdpPoint_Del(UdpPoint*point);intUdpPoint_SendMsg(UdpPoint*point,Message*msg,constchar*remote,intport);intUdpPoint_SendRaw(UdpPoint*point,constchar*buf,intlength,constchar*remote,intport);Message*UdpPoint_RecvMsg(UdpPoint*point,char*remote,int*port);intUdpPoint_RecvRaw((UdpPoint*point,constchar*buf,intlength,char*remote,int*port);intUdpPoint_Available(UdpPoint*point);voidUdpPoint_SetData(UdpPoint*point,void*data);void*UdpPoint_GetData(UdpPoint*point);intUdpPoint_SetOpt(UdpPoint*point,intlevle,intoptname,constvoid*optval,unsignedintoptlen);intUdpPoint_GetOpt(UdpPoint*point,intlevle,intoptname,void*optval,unsignedint*optlen);关键代码实现是UDP以数据报的形式进行通信(不是数据流模式,消息之间有明显的界限),所以不能直接通过MParser_ReadFd(...)解析出消息时,消息必须是完整的先接收到内存中,再从内存中解析出消息,即通过MParser_ReadMeme(...)间接完成消息解析关于上述补充的UDPsocket的发送和接收消息应该使用sendto和recvfrom(类比TCPsocket的connect和accept),参数会标识要发送到的peer,或者是要接收的peer的IP地址和端口;connecttoUDPsocket的行为只会告诉内核:“帮我做一个filter,我只关心这个peer的消息”,已经“connected”的UDPsocket可以使用read,write,recv,发送功能,通常如果确定该实体仅与对等方通信,则选择连接;【更重要的是,UDPsocketbuffer是以消息为单位排队的】,调用一次recvfrom就是提取一条消息,和基于TCP字节流的方式不同。为此,我们不能先读取UDP中的某个应用层头部,然后根据头部长度字段优雅地读取特定数量的数据。这会导致错误和混乱。这通常在TCP中完成。编写程序实验:UDP通信端设计与实际udp_point.h#ifndefUDP_POINT_H#defineUDP_POINT_H#include"message.h"typedefvoidUdpPoint;UdpPoint*UdpPoint_New(intport);UdpPoint*UdpPoint_From(intfd);voidUdpPoint_Del(点);intUdpPoint_SendMsg(UdpPoint*point,Message*msg,constchar*remote,intport);intUdpPoint_SendRaw(UdpPoint*point,constchar*buf,intlength,constchar*remote,intport);Message*UdpPoint_RecvMsg(UdpPoint*point,char*remote,int*port);intUdpPoint_RecvRaw(UdpPoint*point,char*buf,intlength,char*remote,int*port);intUdpPoint_Available(UdpPoint*point);voidUdpPoint_SetData(UdpPoint*点,无效*数据);无效*UdpPoint_GetData(UdpPoint*点);intUdpPoint_SetOpt(UdpPoint*点,intlevle,intoptname,constvoid*optval,unsignedintoptlen);intUdpPoint_GetOpt(UdpPoint*point,intlevle,intoptname,void*optval,unsignedint*optlen);#endif//UDP_POINT_Hudp_point.c#include"udp_point.h"#include"msg_parser.h"#include#include#include#include#include#include#include#includetypedefstructudp_point{intfd;MParser*parser;void*data;}Point;staticcharg_temp[1024*4]={0};staticvoidParserAddr(structsockaddr_inaddr,char*ip,int*port){if(ip){strcpy(ip,inet_ntoa(addr.sin_addr));}if(port){*port=ntohs(addr.sin_port);}}UdpPoint*UdpPoint_New(intport){Point*ret=malloc(sizeof(Point));structsockaddr_inaddr={0};intok=!!ret;addr.sin_family=AF_INET;addr.sin_addr.s_addr=htonl(INADDR_ANY);addr.sin_port=htons(port);ok=ok&&((ret->parser=MParser_New())!=NULL);ok=ok&&((ret->fd=socket(PF_INET,SOCK_DGRAM,0))!=-1);ok=ok&&(bind(ret->fd,(结构sockaddr*)&addr,sizeof(addr))!=-1);if(ok){ret->data=NULL;}否则{退役?(MParser_Del(ret->parser),NULL):NULL;退役?关闭(ret->fd):-1;免费(退役);ret=NULL;}returnret;}UdpPoint*UdpPoint_From(intfd){Point*ret=malloc(sizeof(Point));if(ret){ret->fd=fd;ret->parser=MParser_New();ret->data=NULL;}返回(ret&&ret->解析器)?ret:(free(ret),NULL);}voidUdpPoint_Del(UdpPoint*point){Point*c=(Point*)point;如果(c){关闭(c->fd);MParser_Del(c->解析器);免费(c);}}intUdpPoint_SendMsg(UdpPoint*point,Message*msg,constchar*remote,intport){intret=0;点*c=(点*)点;if(c&&msg&&remote){intlen=Message_Size(msg);char*data=(char*)Message_H2N(味精);ret=UdpPoint_SendRaw(点,数据,len,远程,端口);Message_N2H(味精);返回ret;}intUdpPoint_SendRaw(UdpPoint*point,constchar*buf,intlength,constchar*remote,intport){intret=0;点*c=(点*)点;如果(c&&buf&&remote){structsockaddr_inraddr={0};intaddrlen=sizeof(raddr);raddr.sin_family=AF_INET;raddr.sin_addr.s_addr=inet_addr(远程);raddr.sin_port=htons(端口);ret=(sendto(c->fd,buf,length,0,(structsockaddr*)&raddr,addrlen)!=-1);}returnret;}Message*UdpPoint_RecvMsg(UdpPoint*point,char*remote,int*port){Message*ret=NULL;点*c=(点*)点;如果(c){structsockaddr_inraddr={0};intaddrlen=sizeof(raddr);intlength=recvfrom(c->fd,g_temp,sizeof(g_temp),MSG_PEEK,(structsockaddr*)&raddr,&addrlen);char*buf=(长度>0)?malloc(长度):NULL;length=recvfrom(c->fd,buf,length,0,(structsockaddr*)&raddr,&addrlen);if(length>0){ret=MParser_ReadMem(c->parser,buf,length);}if(ret){ParserAddr(raddr,remote,port);}免费(buf);}returnret;}intUdpPoint_RecvRaw(UdpPoint*point,char*buf,intlength,char*remote,int*port){intret=0;点*c=(点*)点;如果(c&&buf){structsockaddr_inraddr={0};intaddrlen=sizeof(raddr);printf("===============================\n");ret=recvfrom(c->fd,buf,长度,0,(structsockaddr*)&raddr,&addrlen);printf("===============================\n");if(ret!=-1){ParserAddr(raddr,remote,port);}}returnret;}intUdpPoint_Available(UdpPoint*point){intret=-1;点*c=(点*)点;如果(c){结构sockaddr_inraddr={0};intlen=sizeof(raddr);ret=recvfrom(c->fd,g_temp,sizeof(g_temp),MSG_PEEK|MSG_DONTWAIT,(structsockaddr*)&raddr,&len);返回ret;}voidUdpPoint_SetData(UdpPoint*point,void*data){Point*c=(Point*)point;如果(c){c->数据=数据;}}void*UdpPoint_GetData(UdpPoint*point){void*ret=NULL;点*c=(点*)点;如果(c){ret=c->数据;}returnret;}intUdpPoint_SetOpt(UdpPoint*point,intlevle,intoptname,constvoid*optval,unsignedintoptlen){intret=-1;点*c=(点*)点;如果(c){ret=setsockopt(c->fd,levle,optname,optval,optlen);}returnret;}intUdpPoint_GetOpt(UdpPoint*point,intlevle,intoptname,void*optval,unsignedint*optlen){intret=-1;点*c=(点*)点;如果(c){ret=getsockopt(c->fd,levle,optname,optval,optlen);}返还;}输出:p=0x55bd81ba4260ip:192.168.2.24,port:7777msg:0x55bd81ba46e0msg->type=1msg->cmd=2msg->index=3msg->total=4030201tcp_client添加属性相关操作intTcpClient_SetOpt(TcpClient*client,intlevle,intoptname,constvoid*optval,unsignedintoptlen);intTcpClient_GetOpt(TcpClient*client,intlevle,intoptname,void*optval,unsignedint*optlen);//...intTcpClient_SetOpt(TcpClient*client,intlevle,intoptname,constvoid*optval,unsignedintoptlen){intret=-1;客户*c=(客户*)客户;如果(c){ret=setsockopt(c->fd,levle,optname,optval,optlen);}returnret;}intTcpClient_GetOpt(TcpClient*client,intlevle,intoptname,void*optval,unsignedint*optlen){intret=-1;客户*c=(客户*)客户;如果(c){ret=getsockopt(c->fd,levle,optname,optval,optlen);返回ret;}tcp_server添加属性相关操作intTcpClient_SetOpt(TcpServer*server,intlevle,intoptname,constvoid*optval,unsignedintoptlen);intTcpClient_GetOpt(TcpServer*server,intlevle,intoptname,void*optval,unsignedint*optlen);//...intTcpServer_SetOpt(TcpServer*server,intlevle,intoptname,constvoid*optval,unsignedintoptlen){intret=-1;服务器*s=(服务器*)服务器;如果(s){ret=setsockopt(s->fd,levle,optname,optval,optlen);}returnret;}intTcpServer_GetOpt(TcpServer*server,intlevle,intoptname,void*optval,unsignedint*optlen){intret=-1;服务器*s=(服务器*)服务器;如果(s){ret=getsockopt(s->fd,levle,optname,optval,optlen);返回ret;}