1、例程:socKeTsocksrv=socket(AF_IneT,socK_DgRAm,0);charrecvbuf64;socKADDR_Inaddrclient;intlen=sizeof(socKADDR);bufsize=recvfrom(socksrv,recvbuf,sizeof(recvbuf),0,(socKADDR*)2.select函数解析intselect(int,fd_set*,fd_set*,fd_set*,conststructtimeval*);fds:本参数忽略,仅起到兼容作用。readfds:(可选)指针,指向一组等待可读性检查的套接口。writefds:(可选
2、)指针,指向一组等待可写性检查的套接口。exceptfds:(可选)指针,指向一组等待错误检查的套接口。timeout:select()最多等待时间,对阻塞操作则为nuLL。timeout为结构timeval,用来设置select()的等待时间,其结构定义如下structtimevaltime_ttv_sec;/second秒time_ttv_usec;/microsecond微妙;本函数用于确定一个或多个套接口的状态。对每一个套接口,调用者可查询它的可读性、可写性及错误状态信息。用fd_set结构来表示一组等待检查的套接口。FD_cLR(s,*set):从集合set中删除描述字s。FD_Is
3、seT(s,*set):若s为集合中一员,非零;否则为零。FD_seT(s,*set):向集合添加描述字s。FD_ZeRo(*set):将set初始化为空集nuLL。timeout参数控制select()完成的时间。若timeout参数为空指针,则select()将一直阻塞到有一个描述字满足条件。否则的话,timeout指向一个timeval结构,其中指定了select()调用在返回前等待多长时间。如果timeval为0,0,则select()立即返回,这可用于探询所选套接口的状态。如果处于这种状态,则select()调用可认为是非阻塞的。返回值:select()调用返回处于就绪状态并且已经包
4、含在fd_set结构中的描述字总数;如果超时则返回0;否则的话,返回socKeT_eRRoR错误例程:fd_setreadfds;FD_ZeRo(/每次循环都要清空集合,否则不能检测描述符变化FD_seT(sockfd,/添加描述符structtimevaltv;tv.tv_sec=3;/seconds时间的长短和对面数据发送的频率有关tv.tv_usec=50;/microsecondsselect(sockfd+1,3.不用select方式设置非阻塞intimode=1;/0:阻塞1:非阻塞ioctlsocket(sock,FIonbIo,(u_longFAR*)篇二:uDp通信流程uDp
5、发送过程:1应用层:绑定uDp套接字我们必须先创建一个uDp套接字,通过调用udp_new()进行申请,然后调用udp_bind()绑定在uDp端口上,在这个调用过程中,我们必须编写一个用于处理这个uDp套接字接收到的数据报文的函数,并把这个函数作为udp_bind()的参数,以后当套接字接收到数据报文时会自动调用这个函数,我们将在后面介绍这个函数怎么调用的。绑定结束之后,必须调用udp_connect()将数据报文的目的地址绑定在uDp的数据结构中,最后就是调用udp_send()把数据报文发送出去。udp_bind()的处理流程图(:udp接收函数)2传输层的处理做好应用层的处理之后,数据
6、报文被提交到uDp层,udp_send()函数中首先给数据报文加入uDp头部,然后调用ip_route()选择一个合适的网络接口进行发送,最后调用ip_output()把数据报文传入Ip层。3Ip层的处理ip_route()函数比较各个网络接口的Ip地址是否与目的Ip地址在同一子网中,如果有,就把它当成发送的网络接口返回,如果没有就返回一个默认的网络接口。在ip_output()函数中,先给数据报文加上Ip头部,然后比较目的Ip地址与网络接口的Ip地址是否在同一网段,如果不是,就必须先把数据报文发送到网关,于是使用网关的Ip地址作为目的主机,如果目的Ip地址与网络接口的Ip地址在同一网段,则把
7、目的Ip地址作为目的主机。接着调用arp_lookup()在ARp缓存中查找目的主机的mAc地址,找到了调用ethernet_output()把数据报文传入到数据链路层发送,如果找不到,就调用arp_query()发送ARp请求解析目的主机的mAc地址。4ARp协议的处理arp_lookup()实现在本地ARp缓存中查找目的主机的mAc地址,找到了返回该mAc地址,找不到返回nuLL。arp_query()函数中构造一个ARp请求报文,然后调用ethernet_output()把该报文送到数据链路层发送。5数据链路层的处理数据链路层的处理就是给数据报文添上相对的以太网头部,然后调用lowlev
8、er_output()直接把报文传送出去。uDp接收过程:接收过程与发送过程刚好相反,数据报文首先调用ethernet_input()函数到达数据链路层,去掉以太网头部之后如果是ARp报文传给调用arp_input()交给ARp协议处理,如果是Ip报文就调用ip_input()进入Ip层处理,ip_input()函数中比较数据报文的目的Ip地址,如果与某个网络接口的Ip地址相同,则接收这个报文,依照Ip头部的协议字段,调用各自协议的输入处理函数,本例中将调用udp_input(),在udp_input()中提取数据报文的端口号,然后在已登记的套接字中查找与该端口号符合的uDp接收函数,如果没有
9、找到相应的套接字,调用icmp_output()发送一个Icmp不可达报文,如果找到了,就调用该函数(这个函数就是我们在udp_bind()时传入的其中一个参数)。udp_input处理流程图:篇三:uDp收发机制uDp简单聊天程序总结任务一:基于uDp的简单聊天程序实现,采用书上的程序,实现的是客户端发送,服务器端接受,然后发送,如此交替。即这是一个单线程的程序,不能实现同时进行消息的收发。服务器端程序如下:/包含进ws2_32.lib库(也可以直接把链接项包含近来,而不使用下面这句代码)#pragmacomment(lib,ws2_32)voidmain()/绑定套接字bind(socks
10、rv,(socKADDR*)/创建套接字socKeTsocksrv=socket(AF_IneT,socK_DRAm,0);socKADDR_Inaddrsrv;addrsrv.sin_addr.s_un.s_addr=htonl(InADDR_AnY);addrsrv.sin_family=AF_IneT;addrsrv.sin_port=htons(6000);if(LobYTe(wsaData.wVersion)!=1|hIbYTe(wsaData.wVersion)!=1)wsAcleanup();return;err=wsAstartup(wVersionRequested,if(e
11、rr!=0)return;wVersionRequested=mAKewoRD(1,1);/加载套接字库woRDwVersionRequested;wsADATAwsaData;interr;charrecvbuf100;while(1)/等待并接收数据recvfrom(socksrv,recvbuf,100,0,(socKADDR*)if(q=recvbuf0)sprintf(tempbuf,%ssay:%s,inet_ntoa(addrclient.sin_addr),recvbuf);printf(%sn,tempbuf);pleaseinputdata:n);gets(sendbuf)
12、;sendto(socksrv,sendbuf,strlen(sendbuf)+1,0,(socKADDR*)/关闭套接字closesocket(socksrv);wsAcleanup();sendto(socksrv,q,strlen()+1,0,(socKADDR*)printf(chatend!break;charsendbuf100;chartempbuf200;socKADDR_Inaddrclient;intlen=sizof(socKADDR);/发送数据客户端程序如下:/加载套接字库woRDwVersionRequested;err=wsAstartup(wVersionReq
13、uested,if(err!=0)if(LobYTe(wsaData.wVersion)!=1|/创建套接字socKeTsockclient=socket(AF_IneT,socK_DgRAm,0);addrsrv.sin_addr.s_un.s_addr=inet_addr(192.168.188.114charrecvbuf100;intlen=sizeof(socKADDR);while(1)/发送数据printf(sendto(sockclient,sendbuf,strlen(sendbuf)+1,0,(socKADDR*)/等待并接收数据recvfrom(sockclient,re
14、cvbuf,100,0,(socKADDR*)if(q=recvbuf0)sprintf(tempbuf,inet_ntoa(addrsrv.sin_addr),recvbuf);sendto(sockclient,hIbYTe(wsaData.wVersion)!closesocket(sockclient);任务二:在以上程序的基础上作修改,实现同时收发的功能。这就需要用到多线程的概念。思路是:先创建一个互斥对象,然后分别在服务器端和客户端写两个收和发的函数,分别调用waitingforsingleobject函数,以得到这个互斥对象的使用权,等到自己的时间片到了以后再把互斥对象交给另外一
15、个函数。在程序开始处先声明两个线程的入口函数,在主函数中创建两个线程(主函数本身也是一个线程)。但是问题在于在主函数中进行套接字的加载,创建,绑定等一系列操作后,主函数后的两个收,发函数无法调用主函数中定义的套接字。所以在函数开始处就定义套接字,但问题出在下面这两句:hThreadReciev=createThread(nuLL,0,(LpThReAD_sTART_RouTIne)recieve,nuLL,0,nuLL);hThreadsend=createThread(nuLL,0,(LpThReAD_sTART_RouTIne)sending,nuLL,0,nuLL);这两句是正确的,错误
16、的是之前没有把两个收、发函数的起始地址作为createThread函数的第三个参数传给它,所以主函数和另外两个函数之间失去了联系。修改后客户端端的程序如下:voidrecieve();voidsending();socKADDR_Inaddrsrv;socKeTsockclient;intlen;if(LobYTe(wsaData.wVersion)!=1|hIbYTe(wsaData.wVersion)!woRDwVersionRequested;/创建套接字sockclient=socket(AF_IneT,socK_DgRAm,0);127.0.0.1len=sizeof(socKADD
17、R);/发送数据hAnDLehThreadReciev,hThreadsend;hThreadReciev=createThread(nuLL,0,(LpThReAD_sTART_RouTIne)recieve,nuLL,0,nuLL);hThreadsend=createThread(nuLL,0,(LpThReAD_sTART_RouTIne)sending,nuLL,0,nuLL);while(1);closesocket(sockclient);voidrecieve()voidsending()charsendbuf100;while(1)gets(sendbuf);sendto(sockclient,sendbuf,strlen(sendbuf)+1,0,(socKADDR*)charrecvbuf100;while(1)memset(recvbuf,0,sizeof(recvbuf);recvfrom(sockclient,recvbuf,100,0,(socKADDR*)if(recvbuf!=nuLL)puts(recvbuf);由此可见,互斥对象并非是必须的,而且入口函数也不是必须要定义。客户端的程序如下:
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1