UDP客户—服务器程序函数调用,客户不与服务器建立连接,它只管用函数sendto给服务器发送数据报,该函数要求目的地址(服务器)作为其参数。同样的,服务器不从客户接收连接,它只管调用函数recvfrom,等待来自某客户的数据到达,与数据报一起,recvfrom返回客户的协议地址,所以服务器可以发送响应给正确的客户。
在连接中用到的函数:
头文件:
recvfrom:该函数用数据报发送者的协议地址装填由from所指的套接口地址结构,存储在此套接口地址结构中的字节数也以addrlen所指的整数返回给调用者。
sendto:该函数的参数to是一个含有数据将发往的协议地址(例如:IP地址和端口号)的套接口地址结构,它的大小由addrlen来指定。
两个函数都以读写数据的长度作为函数返回值。
注:sendto的最后一个参数值是整数,而recvfrom的最后一个参数是一指向整数值的指针。
代码实现:
//服务器端代码
#include
#include
#include
#include
#include
#include
#include
int main()
{ //UDP专用
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
assert(sockfd != -1);
struct sockaddr_in saddr,caddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6000);
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
assert(res != -1);
while(1)
{
int len = sizeof(caddr);
char buff[128] = {0}; //对方端口的地址
recvfrom(sockfd,buff,127,0,(struct sockaddr*)&caddr,&len);
printf("ip=%s,port=%d,buff=%s\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port),buff);
sendto(sockfd,"ok",2,0,(struct sockaddr*)&caddr,sizeof(caddr));
}
}
#include
#include
#include
#include
#include
#include
#include
int main()
{
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
assert(sockfd != -1);
struct sockaddr_in saddr,caddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6000);
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
while(1)
{
char buff[128] = {0};
printf("input:\n");
fgets(buff,128,stdin);
if(strncmp(buff,"end",3) == 0)
{
break;
}
//给服务器端发送数据
sendto(sockfd,buff,strlen(buff),0,(struct sockaddr*)&saddr,sizeof(saddr));
memset(buff,0,128);
int len = sizeof(caddr);
//服务器给给客户端回复确认信息
recvfrom(sockfd,buff,127,0,(struct sockaddr*)&saddr,&len);
printf("buff = %s\n",buff);
}
close(sockfd);
}
上文提到在UDP套接口编程的时候是不用建立连接的,那么我们就来看一下这个不用连接是怎么来体现的呢
1.我们先打开服务器端和两个客户端,然后进行通信
2.关闭服务器端和其中的一个客户端
3.利用刚刚打开的那个客户端继续给服务器发送数据
4.重启服务器端,再利用客户端给服务器端发送数据
下图就是对上述四点描述的结果展示
在此我们还可以用strace -p + pid 命令可以跟踪系统调用,可以查看程序是阻塞在了哪一步
我们知道TCP和UDP传输数据的时候是有区别的,TCP采用流式服务(这里不再细说,在TCP协议特点里有讲)而UDP采用的是数据报服务,那么我们来看看UDP在传输数据的时候是怎么体现数据报服务的。
根据代码实现的结果截图我们可以看出,(此时服务器端一次只接收一个数据)客户端发送一连串数据给服务器端,第一次服务器端只接收了h,第二次只接收7,那么就有人问了那第一次发送的h以后的数据呢,还有第二次发送的7以后的数据呢?其实这就是UDP传输数据的特点所在,刚说了UDP是数据报服务,那么当规定了它只能读取一定数目的数据之后,无论缓冲区中还有多少数据他都是不能再读的,直接就被丢弃了,下面我们来看看UDP发送和接收缓冲区图
从上面这张图我们可以看出,在UDP发送数据的时候是一次性发送一个数据报,接收的时候也是,并不像TCP那样一下可以把好几个合在一起发送,接收的时候都放在缓冲区里一下可以全部接收,所以在UDP传输数据的过程中,发送次数和接收次数是一对一的。
数据报套接字的优点:服务器的崩溃不会给客户造成不便,也不会要求客户重启,因为基于数据报的服务器通常不保留连接信息,所以它们可以在不打扰其客户的前提下通知并重启。
UDP小结:
(1)UDP以恒定得速度发送数据,如果网不好数据丢了就丢了,比如我们在和亲戚朋友视频聊天得时间就用得是UDP,如果某一时刻得网不好那你俩就都卡住了,或者是一方卡住,但是当网络好了得时候你会发现你俩在实时交流,并没有产生延迟,如果是TCP得话,他的数据如果没有传过去就会一直从传,知道收到确认后才会继续发送后面得数据,这样得话你就会发现即使网好了,你俩也不能在同一时刻交流,他之前说的话可能现在才传过来,他此刻说的你却还不能接收到。
(2)如果非要用UDP实现一个TCP得可靠传输得功能那么我们就参考TCP在应用层实现一个可靠得机制