【软件通信协议】2. 详细解析UDP通信协议(附广播 组播)

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协议了。

扫描二维码关注公众号,回复: 10111406 查看本文章

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

 

发布了41 篇原创文章 · 获赞 54 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/sishuihuahua/article/details/88929449