郑州网站建设扌汉狮网络,国内商务网络公司排名,思明区建设局官网站,wordpress 模版标签一、什么是UDP组播 UDP组播是指使用用户数据报协议#xff08;UDP#xff09;实现的组播方式。组播是一种数据传输方式#xff0c;允许单一数据包同时传输到多个接收者。在UDP组播中#xff0c;一个数据包可以被多个接收者同时接收#xff0c;这样可以降低网络传输的负载和…一、什么是UDP组播 UDP组播是指使用用户数据报协议UDP实现的组播方式。组播是一种数据传输方式允许单一数据包同时传输到多个接收者。在UDP组播中一个数据包可以被多个接收者同时接收这样可以降低网络传输的负载和提高数据传输效率。
二、特性 1、支持单向的多对多通信UDP组播可以同时将一个数据包传输给多个接收者使多个接收者能够同时获取到相同的数据。 2、不可靠性跟普通的UDP一样UDP组播只提供不可靠的数据传输服务。如果某个接收者没有接收到数据包发送者不会得到任何提示或反馈信息。 3、可扩展性UDP组播支持动态加入和退出组播组能够自适应地处理组播成员的加入和离开聊天群里的进群和退群操作。 4、低延迟UDP组播传输的数据包不需要在接收方重新组装可以直接进行处理因此具有很低的传输延迟。 5、高效UDP组播传输的数据包只需要经过一次发送操作就可以同时传输到多个接收者可以有效地降低网络传输的负载。 6、简单易用UDP组播不需要复杂的配置和管理使用简单能够快速搭建起基于组播的多媒体通信系统。
三、使用场景 1、多媒体流媒体UDP组播可以在局域网或广域网上传输音视频流能够快速地向多个接收者发送相同的视频和音频数据避免了建立多个点对点的连接。 2、 分布式应用的数据分发UDP组播可以实现高效的数据分发例如在大型集群环境下可以将某些服务的状态信息广播给所有节点使得所有节点都能够及时了解到最新的信息。 3、网络游戏UDP组播可以用于多人联机游戏使得多个玩家能够同时收到相同的游戏状态和动作提高游戏体验。 4、 网络广播UDP组播可以用于向多个设备广播事件和消息例如路由器可以向所有连接的设备发送网络配置信息、DHCP服务器可以向所有设备广播IP地址信息等。 5、实时数据更新UDP组播可以用于实时的数据更新例如在金融行业可以订阅某些财经数据的实时更新以便及时响应市场变化。 可以把UDP组播简单理解为群聊。
四、UDP组播通信流程 1、发送方 1、建立套接字。使用socket() 2、设置端口复用。使用setsockopt()可选推荐 3、绑定自己的IP地址和端口号。使用bind()可以省略 4、发送数据接收方IP地址要填写为组播地址。使用sendto() 5、关闭套接字。使用close() 2、接收方 1、建立套接字。使用socket() 2、定义并初始化一个组播结构体。使用struct ip_mreq; 3、给套接字加入组播属性。使用setsockopt() 4、绑定自己的IP地址和端口号。使用bind()不可以省略 5、接收数据。使用recvfrom() 6、关闭套接字。使用close()
五、相关函数API 1、建立套接字 // 建立套接字
int socket(int domain, int type, int protocol);// 接口说明返回值成功返回一个套接字文件描述符失败返回-1参数domain用来指定使用何种地址类型有很多具体看别的资源1PF_INET 或者 AF_INET 使用IPV4网络协议2其他很多的看别的资源参数type通信状态类型选择有很多具体看别的资源1SOCK_STREAM 提供双向连续且可信赖的数据流即TCP2SOCK_DGRAM 使用不连续不可信赖的数据包连接即UDP参数protocol用来指定socket所使用的传输协议编号通常不用管一般设为0 2、设置端口状态 // 设置端口的状态
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);// 接口说明返回值成功返回0失败返回-1参数sockfd待设置的套接字参数level 待设置的网络层一般设成为SOL_SOCKET以存取socket层参数optname待设置的选项有很多种具体看别的资源这里讲常用的1、SO_REUSEADDR 允许在bind()过程中本地地址可复用即端口复用2、SO_BROADCAST 使用广播的方式发送通常用于UDP广播3、SO_SNDBUF 设置发送的暂存区大小4、SO_RCVBUF 设置接收的暂存区大小5、IP_ADD_MEMBERSHIP 设置为组播参数optval待设置的值参数optlen参数optval的大小即sizeof(optval)// 组播结构体
struct ip_mreq
{struct in_addr imr_multiaddr; // 多播组的IP地址就是组播的IP地址struct in_addr imr_interface; // 需要加入到组的IP地址就是自己的IP地址
}; 3、绑定IP地址和端口号 // 绑定自己的IP地址和端口号int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);// 接口说明返回值参数sockfd待绑定的套接字参数addrlen参数addr的大小即sizeof(addr)参数addrIP地址和端口的结构体通用的结构体根据sockfd的类型有不同的定义当sockfd的domain参数指定为IPV4时结构体定义为struct sockaddr_in{unsigned short int sin_family; // 需与sockfd的domain参数一致uint16_t sin_port; // 端口号struct in_addr sin_addr; // IP地址 unsigned char sin_zero[8]; // 保留的未使用};struct in_addr{uin32_t s_addr;}
// 注意网络通信时采用大端字节序所以端口号和IP地址需要调用专门的函数转换成网络字节序 4、字节序转换接口 // 第一组接口
// 主机转网络IP地址输入主机IP地址
uint32_t htonl(uint32_t hostlong);// 主机转网络端口输入主机端口号
uint16_t htons(uint16_t hostshort); // 常用// 网络转主机IP输入网络IP地址
uint32_t ntohl(uint32_t netlong);// 网络转主机端口输入网络端口
uint16_t ntohs(uint16_t netshort);// 第二组接口只能用于IPV4转换IP地址
// 主机转网络
int inet_aton(const char *cp, struct in_addr *inp);// 主机转网络
in_addr_t inet_addr(const char *cp); // 常用// 网络转主机
int_addr_t inet_network(const char *cp);// 网络转主机
char *inet_ntoa(struct in_addr in); // 常用// 将本地IP地址转为网络IP地址
int inet_pton(int af, const char *src, void *dst);
// 参数说明参数af选择是哪一种协议族IPV4还是IPV6参数src本地IP地址参数dst将本地IP地址转为网络IP地址存储到这里5、发送数据 // UDP协议发送数据
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);// 接口说明返回值成功返回成功发送的字节数失败返回-1参数sockfd发送者的套接字参数buf发送的数据缓冲区参数len发送的长度参数flags一般设置为0还有其他数值具体查询别的资源参数dest_addr接收者的网络地址参数addrlen接收者的网络地址大小即sizeof(dest_addr) 6、接收数据 // UDP协议接收数据
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);// 接口说明返回值成功返回成功接收的字节数失败返回-1参数sockfd接收者的套接字参数buf接收数据缓的冲区参数len接收的最大长度参数flags一般设置为0还有其他数值具体查询别的资源参数src_addr发送者的网络地址可以设置为NULL参数addrlen 发送者的网络地址大小即sizeof(src_addr) 7、关闭套接字 // 关闭套接字
int close(int fd);// 接口说明返回值成功返回0失败返回-1参数fd套接字文件描述符 六、案例 实现UDP组播的演示 发送端GroupSend.c // UDP组播发送方的案例#include stdio.h
#include unistd.h
#include string.h
#include sys/types.h
#include sys/socket.h
#include netinet/in.h
#include netinet/ip.h
#include arpa/inet.h#define SEND_IP 192.168.64.128 // 记得改为自己IP
#define SEND_PORT 10000 // 不能超过65535也不要低于1000防止端口误用int main(int argc, char *argv[])
{// 1、建立套接字使用IPV4网络地址UDP协议int sockfd socket(AF_INET, SOCK_DGRAM, 0);if(sockfd -1){perror(socket fail);return -1;}// 2、设置端口复用推荐int optval 1; // 这里设置为端口复用所以随便写一个值int ret setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, optval, sizeof(optval));if(ret -1){perror(setsockopt fail);close(sockfd);return -1;}// 3、绑定自己的IP地址和端口号可以省略struct sockaddr_in send_addr {0};socklen_t addr_len sizeof(struct sockaddr);send_addr.sin_family AF_INET; // 指定协议为IPV4地址协议send_addr.sin_port htons(SEND_PORT); // 端口号send_addr.sin_addr.s_addr inet_addr(SEND_IP); // IP地址ret bind(sockfd, (struct sockaddr*)send_addr, addr_len);if(ret -1){perror(bind fail);close(sockfd);return -1;}// 4、发送数据往组播地址uint16_t port 0; // 端口号char ip[20] {0}; // IP地址struct sockaddr_in recv_addr {0};char msg[128] {0}; // 数据缓冲区// 注意输入组播地址范围是D类网络地址224.0.0.1~239.255.255.254printf(please input receiver IP and port\n);scanf(%s %hd, ip, port);printf(IP %s, port %hd\n, ip, port);recv_addr.sin_family AF_INET; // 指定用IPV4地址recv_addr.sin_port htons(port); // 接收者的端口号recv_addr.sin_addr.s_addr inet_addr(ip); // 接收者的IP地址while(getchar() ! \n); // 清空多余的换行符while(1){printf(please input data:\n);fgets(msg, sizeof(msg)/sizeof(msg[0]), stdin);// 发送数据注意要填写接收者的地址ret sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr*)recv_addr, addr_len);if(ret 0){printf(success: send %d bytes\n, ret);}}// 5、关闭套接字close(sockfd);return 0;
} 接收端GroupRecv.c // UDP组播接收方的案例#include stdio.h
#include unistd.h
#include string.h
#include sys/types.h
#include sys/socket.h
#include netinet/in.h
#include netinet/ip.h
#include arpa/inet.h#define RECV_IP 192.168.64.128 // 记得改为自己的地址#define GROUP_IP 224.0.0.10 // 组播地址
#define GROUP_PORT 20000 // 不能超过65535也不要低于1000防止端口误用int main(int argc, char *argv[])
{// 1、建立套接字使用IPV4网络地址UDP协议int sockfd socket(AF_INET, SOCK_DGRAM, 0);if(sockfd -1){perror(socket fail);return -1;}// 2、定义并初始化一个组播结构体设置组播IPstruct ip_mreq vmreq;inet_pton(AF_INET, GROUP_IP, vmreq.imr_multiaddr); // 初始化组播地址inet_pton(AF_INET, RECV_IP, vmreq.imr_interface); // 把自己的地址加入到组中// 3、给套接字加入组播属性int ret setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, vmreq, sizeof(vmreq));if(ret -1){perror(setsockopt fail);close(sockfd);return -1;}// 4、绑定自己的IP地址和端口号不可以省略struct sockaddr_in recv_addr {0};socklen_t addr_len sizeof(struct sockaddr);recv_addr.sin_family AF_INET; // 指定协议为IPV4地址协议recv_addr.sin_port htons(GROUP_PORT); // 端口号注意绑定为组播的端口号// recv_addr.sin_addr.s_addr inet_addr(RECV_IP); // IP地址. 写下面的更好recv_addr.sin_addr.s_addr htonl(INADDR_ANY); // 本机内所有的IP地址ret bind(sockfd, (struct sockaddr*)recv_addr, addr_len);if(ret -1){perror(bind fail);close(sockfd);return -1;}// 4、接收数据uint16_t port 0; // 端口号char ip[20] {0}; // IP地址struct sockaddr_in send_addr {0};char msg[128] {0}; // 数据缓冲区while(1){// 接收数据注意使用发送者的地址来接收ret recvfrom(sockfd, msg, sizeof(msg)/sizeof(msg[0]), 0, (struct sockaddr*)send_addr, addr_len);if(ret 0){memset(ip, 0, sizeof(ip)); // 先清空IPstrcpy(ip, inet_ntoa(send_addr.sin_addr)); // 网络IP转主机IPport ntohs(send_addr.sin_port); // 网络端口号转主机端口号printf([%s:%d] send data: %s\n, ip, port, msg);memset(msg, 0, sizeof(msg)); // 清空数据区}}// 5、关闭套接字close(sockfd);return 0;
} 通信演示 注第一幅图只有一台主机不好演示第二幅图有两台主机一台本机另外一台用ssh连接实现了组播。
七、总结 组播是一种数据传输方式允许单一数据包同时传输到多个接收者。在UDP组播中一个数据包可以被多个接收者同时接收这样可以降低网络传输的负载和提高数据传输效率。组播主要应用以群聊的场景。UDP组播的通信流程跟UDP的广播的通信流程大致相同但是要注意组播接收方要定义一个组播结构体然后把自己的IP地址加入到组播中。可以结合案例加深对组播的理解。