目录
1.UDP编程流程
2.recvfrom()、sento()
3.代码演示
3.udp特点
1.UDP编程流程
socket()用来创建套接字,使用 udp 协议时,选择数据报服务 SOCK_DGRAM。sendto()用来发送数据,由于 UDP 是无连接的,每次发送数据都需要指定对端的地址(IP和端口)。recvfrom()接收数据,每次都需要传给该方法一个地址结构来存放发送端的地址。recvfrom()可以接收所有客户端发送给当前应用程序的数据,并不是只能接收某一个客户端的数据。
2.recvfrom()、sento()
UDP 数据读写:
recvfrom()读取 sockfd 上的数据, buff 和 len 参数分别指定读缓冲区的位置和大小
ssize_t recvfrom(int sockfd, void *buff, size_t len, int flags.struct sockaddr* src_addr,socklen_t* addrlen);
- src_addr 记录发送端的 socket 地址
- addrlen 指定该地址的长度
sendto()往 socket 上写入数据, buff 和 len 参数分别指定写缓冲区的位置和数据长度
ssize_t sendto(int sockfd, void *buff, size_t len, int flags,struct sockaddr* dest_addr,socklen_t addrlen);
- dest_addr 指定接收数据端的 socket 地址
- addrlen 指定该地址的长度
3.代码演示
服务器代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>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");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("buff=%s\n",buff);sendto(sockfd,"ok",2,0,(struct sockaddr*)&caddr,sizeof(caddr));}close(sockfd);exit(0);
}
客户端代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>int main()
{int sockfd=socket(AF_INET,SOCK_DGRAM,0);assert(sockfd!=-1);struct sockaddr_in saddr;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){printf("input:\n");int len=sizeof(saddr);char buff[128]={0};fgets(buff,127,stdin);if(strncmp(buff,"end",3)==0){break;}sendto(sockfd,buff,strlen(buff),0,(struct sockaddr*)&saddr,sizeof(saddr));memset(buff,0,128);recvfrom(sockfd,buff,127,0,(struct sockaddr*)&saddr,&len);printf("buff=%s\n",buff);}close(sockfd);exit(0);
}
运行结果:
3.udp特点
无链接的,不可靠的,数据报服务
1)多个客户端可以同时给服务器发送数据(因为没有建立链接,也就是说服务器没有只和某一个客户端建立链接);
2)服务器关掉再打开是可以接收数据的;(因为没有建立链接)
如果在服务器关闭时发送信息,会阻塞,在服务器再次开机时不会收到这条消息。客户端因为上条消息阻塞,不能再向服务器发送消息。
3)数据报接收的特点:
用户数据报协议UDP只在IP的数据报服务之上增加了很少一点的功能,这就是复用和分用的功能以及差错检测的功能.
(复用:多个用户使用一个IO资源发送消息;分用:多个用户使用一个IO资源接收消息)
UDP是面向报文的,发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付给IP层.UDP对应用层交下来的报文,即不合并,也不拆分,而是保留这些报文的边界.
这就是说,应用层交给UDP多长的报文,UDP就照样发送,即一次发送一个报文,如下图所示.
在接收方的UDP,对IP层交上来的UDP用户数据报,在去掉首部后就原封不动地交付给上层地应用进程也就是说,UDP一次交付一个完整的报文
因此,应用程序必须选择合适大小的报文.若报文太长,UDP把它交给IP层后,IP层在传送时可能要进行分片,这会降低IP层的效率.反之,若报文太短,UDP把它交给IP层后,会使IP数据报的首部的相对长度太大,这也降低了IP层的效率.
UDP 数据报服务特点:发送端应用程序每执行一次写操作,UDP 模块就将其封装成一个 UDP 数据报发送。接收端必须及时针对每一个 UDP 数据报执行读操作,否则就会丢包。并且,如果用户没有指定足够的应用程序缓冲区来读取 UDP 数据,则UDP 数据将被截断。
也就是udp协议sendto和recvfrom的次数是相同的,不会出现沾包;
(TCP:传输控制协议)
对比TCP字节流服务特点:
UDP的其他特点:
(1)UDP没有拥塞控制,因此网络上出现的拥塞不会使源主机的发送速率降低,这对某些实时应用是很重要的.很多的实时应用(如IP电话,实时视频会议等)要求源主机以恒定的速率发送数据,并且允许在网络发生拥塞时丢失一些数据,但却不允许数据有太大的时延.UDP正好适合这种要求.
虽然某些实时应用需要使用没有拥塞控制的UDP,但当很多的源主机同时都向网络发送高速率的实时视频流时,网络就有可能发生拥塞,结果大家都无法正常接收。因此,不使用拥塞控制功能的 UDP有可能会引起网络产生严重的拥塞问题。
还有一些使用 UDP的实时应用,需要对 UDP的不可靠的传输进行适当的改进,以减少数据的丢失。在这种情况下,应用进程本身可以在不影响应用的实时性的前提下,增加一些提高可靠性的措施,如采用前向纠错或重传已丢失的报文。
(2)UDP支持一对一,一对多,多对一,多对多的交互通信
(3)UDP的首部开销小,只有8个字节,比TCP的20个字节的首部短。
总结UDP主要特点
UDP 是无连接的,即发送数据之前不需要建立连接
UDP 尽最大努力交付,不保证可靠交付,不支持拥塞控制
UDP 面向报文,没有拥塞控制,很适合多媒体通信的要求
UDP 支持一对一,一对多,多对一和多对多的交互通信
UDP 首部开销小,只有8个字节