1. UDP协议简介
UDP是User Datagram Protocol的简称,全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。UDP用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的客户/服务器模式的网络应用都需要使用UDP协议。UDP协议从问世至今已经被使用了很多年,虽然其最初的光彩已经被一些类似协议所掩盖,但是即使是在今天UDP仍然不失为一项非常实用和可行的网络传输层协议(百度百科定义)。
2. UDP协议的特点及应用
UDP的过程类似于寄信,只需要目的地址(ip和端口号),就可以寄出,但是不保证信件到不到达。
(1)无连接:知道对端的IP和端口号就直接进行传输,不需要建立连接
(2)不可靠:没有确认机制,没有重传机制;如果因为网络故障无法发到对方UDP协议也不会给应用层返回任何错误信息
(3)面向数据报:不能灵活的控制读写数据的次数和数量,应用层交给UDP多长的报文,UDP原样发送,既不会拆分也不会合并。
UDP的缓冲区
(1)UDP没有真正意义上的缓冲区,调用sendto会直接发送给内核,由内核将数据传与网络层协议进行后续的传输动作
(2)UDP具有接收缓冲区,但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致;如果缓冲区满了,再到达的数据就会被丢弃
UDP的socket既能读也能写,这个概念叫做全双工 。
基于UDP的应用层协议有:
(1)NFS:网络文件系统
(2)TFTP:简单文件传输协议
(3)DHCP:动态主机配置协议
(4)BOOTP:启动协议(用于无盘设备启动)
(5)DNS:域名解析协议
更加直观一些的说法就是:好比视频流、实时通信,追求速度,但是对数据要求不是非常严格的通信,视频可以丢帧,消息可能会到达不了是可以接收的;但是如果是一些机密的数据,那么必须要保证数据的准确性,那么就需要使用TCP协议了。
3. 简单的UDP协议CS模型
由以上框图可以看出,客户端要发起一次请求,仅仅需要两个步骤(socket和sendto),而服务器端也仅仅需要三个步骤即可接收到来自客户端的消息(socket、bind、recvfrom)。
UDP的C/S模型Linux C Demo代码请移步本人github:
https://github.com/ZhenhuaWei/Linux-C-Demo.git
4. UDP广播
同时发给局域网中的所有主机,称为广播。
4.1、广播地址
某个网段的最大主机地址代表该网段的广播地址。
以192.168.1.0 (255.255.255.0) 网段为例,最大的主机地址192.168.1.255代表该网段的广播地址;发到该地址的数据包被该网段内所有的主机接收
255.255.255.255在所有网段中都代表广播地址
4.2、广播发送(广播IP)流程
1) 创建用户数据报套接字
2) 缺省创建的套接字不允许广播数据包,需要设置属性: setsockopt可以设置套接字属性
3)接收方地址指定为广播地址
4)指定端口信息
5)发送数据包
int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
头文件:#include<sys/socket.h>
参数: level : 选项级别(例如SOL_SOCKET)
optname : 选项名(例如SO_BROADCAST)
optval : 存放选项值的缓冲区的地址
optlen : 缓冲区长度
返回值:成功返回0 失败返回-1并设置errno
4.3、广播接收流程
1) 创建用户数据报套接字
2) 绑定本机IP地址和端口
绑定的端口必须和发送方指定的端口相同
3)等待接收数据
Linux C Demo请移步到本人github:
https://github.com/ZhenhuaWei/Linux-C-Demo.git
5. UDP多播(组播)
含义:组播(又称为多播)是一种折中的方式,只有加入某个多播组的主机才能收到数据。
优点:多播方式既可以发给多个主机,又能避免象广播那样带来过多的负载(每台主机要到传输层才能判断广播包是否要处理),可以是局域网也可以是广域网。
5.1 组播发送(指定组播IP(D类地址))
1) 创建用户数据报套接字
2) 接收方地址指定为组播地址(D类地址)
// 第一步:使能广播属性
int on = 1;
Setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST,&on, sizeof on);
// 第二步:往约定好的组播地址发送消息
bzero(&peeraddr, sizeof(peeraddr));
peeraddr.sin_family = PF_INET;
peeraddr.sin_port = htons(atoi(argv[2]));
peeraddr.sin_addr.s_addr = inet_addr(argv[1]);
3) 指定端口信息
4) 发送数据包
5.2 组播接受(加入组播IP)
1) 创建用户数据报套接字
2) 加入多播组
struct ip_mreq mreq;
bzero(&mreq, sizeof mreq);
// 以下IP地址指明组播ID
mreq.imr_multiaddr.s_addr = inet_addr(argv[1]);
// 以下IP地址指明接收组播消息的网络接口
// INADDR_ANY表示任意网络接口,因为目前电脑只有一个接口
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
Setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof mreq);
3) 绑定本机IP地址和端口: 绑定的端口必须和发送方指定的端口相同
4) 等待接收数据
5.3 组播地址结构体封装
struct ip_mreq
{
struct in_addr imr_multiaddr;
struct in_addr imr_interface;
};
struct ip_mreq mreq;
bzero(&mreq, sizeof(mreq));
mreq.imr_multiaddr.s_addr = inet_addr(“224.10.10.1”);//
mreq.imr_interface.s_addr = htonl(INADDR_ANY); //
inet_pton(AF_INET,”192.168.7.89”, (void *)& mreq.imr_interface);//
setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
Linux C Demo请移步到本人github:
https://github.com/ZhenhuaWei/Linux-C-Demo.git