udp接收函数Word格式文档下载.docx
《udp接收函数Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《udp接收函数Word格式文档下载.docx(5页珍藏版)》请在冰豆网上搜索。
例程:
socKeTsocksrv=socket(AF_IneT,socK_DgRAm,0);
charrecvbuf[64];
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:
(可选)指针,指向一组等待可写性检查的套接口。
exceptfds:
(可选)指针,指向一组等待错误检查的套接口。
timeout:
select()最多等待时间,对阻塞操作则为nuLL。
timeout为结构timeval,用来设置select()的等待时间,其结构定义如下
structtimeval{
time_ttv_sec;
//second秒
time_ttv_usec;
//microsecond微妙
};
本函数用于确定一个或多个套接口的状态。
对每一个套接口,调用者可查询它的可读性、可写性及错误状态信息。
用fd_set结构来表示一组等待检查的套接口。
FD_cLR(s,*set):
从集合set中删除描述字s。
FD_IsseT(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()调用返回处于就绪状态并且已经包含在fd_set结构中的描述字总数;
如果超时则返
回0;
否则的话,返回socKeT_eRRoR错误
例程:
fd_setreadfds;
FD_ZeRo(//每次循环都要清空集合,否则不能检测描述符变化FD_seT(sockfd,//添加描述符
structtimevaltv;
tv.tv_sec=3;
//seconds时间的长短和对面数据发送的频率有关
tv.tv_usec=50;
//microseconds
select(sockfd+1,
3.不用select方式设置非阻塞
intimode=1;
//0:
阻塞1:
非阻塞
ioctlsocket(sock,FIonbIo,(u_longFAR*)
篇二:
uDp通信流程
uDp发送过程:
1.应用层:
绑定uDp套接字我们必须先创建一个
uDp套接字,通过调用udp_new()进行申请,然后调用udp_bind()绑定在uDp端口上,在这个调用过程中,我们必须编写一个用于处理这个uDp套接字接收到的数据报文的函数,并把这个函数作为
udp_bind()的参数,以后当套接字接收到数据报文时会自动调用这个函数,我们将在后面介绍这个函数怎么调用的。
绑定结束之后,必须调用
udp_connect()将数据报文的目的地址绑定在uDp的数据结构中,最后就是调用udp_send()把数据报文发送出去。
udp_bind()的处理流程图
(:
udp接收函数) 2.传输层的处理
做好应用层的处理之后,数据报文被提交到uDp层,udp_send()函数中首先给数据报文加入uDp头部,然后调用ip_route()选择一个合适的网络接口进行发送,最后调用ip_output()把数据报文传入Ip层。
3.Ip层的处理
ip_route()函数比较各个网络接口的Ip地址是否与目的Ip地址在同一子网中,如果有,就把它当成发送的网络接口返回,如果没有就返回一个默认的网络接口。
在ip_output()函数中,先给数据报文加上Ip头部,然后比较目的Ip地址与网络接口的Ip地址是否在同一网段,如果不是,就必须先把数据报文发送到网关,于是使用网关的Ip地址作为目的主机,如果目的Ip地址与网络接口的Ip地址在同一网段,则把目的Ip地址作为目的主机。
接着调用arp_lookup()在ARp缓存中查找目的主机的mAc地址,找到了调用ethernet_output()把数据报文传入到数据链路层发送,如果找不到,就调用arp_query()发送ARp请求解析目的主机的mAc地址。
4.ARp协议的处理
arp_lookup()实现在本地ARp缓存中查找目的主机的mAc地址,找到了返回该mAc地址,找不到返回nuLL。
arp_query()函数中构造一个ARp请求报文,然后调用ethernet_output()把该报文送到数据链路层发送。
5.数据链路层的处理
数据链路层的处理就是给数据报文添上相对的以太网头部,然后调用lowlever_output()直接把报文传送出去。
uDp接收过程:
接收过程与发送过程刚好相反,数据报文首先调用ethernet_input()函数到达数据链路层,去掉以太网头部之后如果是ARp报文传给调用arp_input()交给ARp协议处理,如果是Ip报文就调用ip_input()进入Ip层处理,ip_input()函数中比较数据报文的目的Ip地址,如果与某个网络接口的Ip地址相同,则接收这个报文,依照Ip头部的协议字段,调用各自协议的输入处理函数,本例中将调用udp_input(),在udp_input()中提取数据报文的端口号,然后在已登记的套接字中查找与该端口号符合的uDp接收函数,如果没有找到相应的套接字,调用icmp_output()发送一个Icmp不可达报文,如果找到了,就调用该函数(这个函数就是我们在udp_bind()时传入的其中一个参数)。
udp_input
处理流程图:
篇三:
uDp收发机制
uDp简单聊天程序总结
任务一:
基于uDp的简单聊天程序实现,采用书上的程序,实现的是客户端发送,服务器端接受,然后发送,如此交替。
即这是一个单线程的程序,不能实现同时进行消息的收发。
服务器端程序如下:
//包含进ws2_32.lib库(也可以直接把链接项包含近来,而不使用下面这句代码)
#pragmacomment(lib,"
ws2_32"
)
voidmain()
{
//绑定套接字bind(socksrv,(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(err!
=0){}return;
wVersionRequested=mAKewoRD(1,1);
//加载套接字库woRDwVersionRequested;
wsADATAwsaData;
interr;
charrecvbuf[100];
}
while
(1)
//等待并接收数据recvfrom(socksrv,recvbuf,100,0,(socKADDR*)if(q==recvbuf[0]){}sprintf(tempbuf,"
%ssay:
%s"
inet_ntoa(addrclient.sin_addr),recvbuf);
printf("
%s\n"
tempbuf);
pleaseinputdata:
\n"
);
gets(sendbuf);
sendto(socksrv,sendbuf,strlen(sendbuf)+1,0,(socKADDR*)//关闭套接字closesocket(socksrv);
wsAcleanup();
sendto(socksrv,"
q"
strlen("
)+1,0,(socKADDR*)printf("
chatend!
break;
charsendbuf[100];
chartempbuf[200];
socKADDR_Inaddrclient;
intlen=sizof(socKADDR);
//发送数据
客户端程序如下:
//加载套接字库woRDwVersionRequested;
err=wsAstartup(wVersionRequested,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.114"
charrecvbuf[100];
intlen=sizeof(socKADDR);
while
(1){}//发送数据printf("
sendto(sockclient,sendbuf,strlen(sendbuf)+1,0,(socKADDR*)//等待并接收数据recvfrom(sockclient,recvbuf,100,0,(socKADDR*)if(q==recvbuf[0]){}sprintf(tempbuf,"
inet_ntoa(addrsrv.sin_addr),recvbuf);
sendto(sockclient,"
hIbYTe(wsaData.wVersion)!
closesocket(sockclient);
任务二:
在以上程序的基础上作修改,实现同时收发的功能。
这就需要用到多线程的概念。
思路是:
先创建一个互斥对象,然后分别在服务器端和客户端写两个收和发的函数,分别调用waitingforsingleobject函数,以得到这个互斥对象的使用权,等到自己的时间片到了以后再把互斥对象交给另外一个函数。
在程序开始处先声明两个线程的入口函数,在主函数中创建两个线程(主函数本身也是一个线程)。
但是问题在于在主函数中进行套接字的加载,创建,绑定等一系列操作后,主函数后的两个收,发函数无法调用主函数中定义的套接字。
所以在函数开始处就定义套接字,但问题出在下面这两句:
hThreadReciev=createThread(nuLL,0,(LpThReAD_sTART_RouTIne)recieve,nuLL,0,nuLL);
hThreadsend=createThread(nuLL,0,(LpThReAD_sTART_RouTIne)sending,nuLL,0,nuLL);
这两句是正确的,错误的是之前没有把两个收、发函数的起始地址作为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.1"
len=sizeof(socKADDR);
//发送数据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()
charsendbuf[100];
while
(1){}
}gets(sendbuf);
sendto(sockclient,sendbuf,strlen(sendbuf)+1,0,(socKADDR*)charrecvbuf[100];
while
(1){}memset(recvbuf,0,sizeof(recvbuf));
recvfrom(sockclient,recvbuf,100,0,(socKADDR*)if(recvbuf!
=nuLL)puts(recvbuf);
由此可见,互斥对象并非是必须的,而且入口函数也不是必须要定义。
客户端的程序如下: