14.5 Socket 应用组播通信

socket,应用,通信 · 浏览次数 : 1

小编点评

**组播通信** 组播通信是一种基于 UDP 协议的网络通信方式,允许发送方将消息同时传递给多个接收方。 **服务端代码** 1. 创建套接字,指定组名。 2. 设置组播模式。 3. 循环接收数据包并将其发送给客户端。 **客户端代码** 1. 创建套接字,指定组名。 2. 发送数据包。 3. 接收组播数据包并打印。 **组播通信的关键参数** * **IP 地址范围**:用于分组的 IP 地址。 * **组名**:用于分组的名称。 * **套接字**:用于通信的套接字。 **示例** **服务端代码** ```c++ #include #include int main() { // 初始化套接字 WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); // 创建套接字 SOCKET fd = socket(AF_INET, SOCK_DGRAM, 0); // 设置组播模式 setsockopt(fd, SOL_SOCKET_SO_BROADCAST, 1); // 循环接收数据包 while (1) { // 接收数据包 int addrlen = sizeof(struct sockaddr_in); char recv_buffer[4096]; recvfrom(fd, recv_buffer, 4096, 0, (struct sockaddr *) &addr, &addrlen); // 打印接收的数据包 std::cout << "接收组播数据包: " << recv_buffer << std::endl; } // 关闭套接字 closesocket(fd); // 结束程序 return 0; } ``` **客户端代码** ```c++ #include #include int main() { // 初始化套接字 WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); // 创建套接字 SOCKET fd = socket(AF_INET, SOCK_DGRAM, 0); // 设置组播模式 setsockopt(fd, SOL_SOCKET_SO_BROADCAST, 1); // 发送数据包 char send_buffer[4096] = "Hello, World!"; sendto(fd, send_buffer, strlen(send_buffer), 0, (struct sockaddr *) NULL, 0); // 接收数据包 int addrlen = sizeof(struct sockaddr_in); char recv_buffer[4096] = { 0 }; recvfrom(fd, recv_buffer, 4096, 0, (struct sockaddr *) NULL, &addrlen); // 打印接收的数据包 std::cout << "接收组播数据包: " << recv_buffer << std::endl; // 关闭套接字 closesocket(fd); // 结束程序 return 0; } ```

正文

组播通信是一种基于UDP协议的网络通信方式,它允许发送方将消息同时传递给多个接收方。在组播通信中,发送方和接收方都会加入一个共同的组播组,这个组播组对应一个特定的IP地址,所有加入该组播组的主机都能够接收到发送方发送的消息。组播通信可以有效地减少网络流量和网络负载,因为在传统的点对点通信方式下,每个消息都需要单独传输到每个接收方,而在组播通信中,每个消息只需要传输一次,就可以同时传递给多个接收方。

在使用组播模式时,需要在套接字上使用setsockopt()函数来设置套接字的IP_MULTICAST_IF选项,指定本地主机的出站接口地址,用于发送组播数据包。此外,还可以设置IP_ADD_MEMBERSHIP选项,将套接字加入到一个特定的组播组中,以便接收该组播组中的数据包。

在使用组播模式时需要读者注意,组播模式需要使用特定的IP地址范围,如224.0.0.0~239.255.255.255,且需要确保组播组内的所有成员都在同一个网络中。同时,组播模式也不保证数据传输的可靠性,因为UDP本身就是无连接的协议,所以需要在应用程序中自行处理数据丢失或重复的情况。

14.5.1 服务端实现

先来实现服务端代码,首先我们定义一个端口号PORT=9999并定义好组名GROUP="225.1.2.3",接着通过调用两次setsockopt函数,第一次调用指定传入SO_REUSEADDR参数设置为组播模式,第二次调用指定传入IP_ADD_MEMBERSHIP用于设置组,经过两次设置服务端将被绑定到GROUP指定的组名上面,并在底部recvfrom循环等待数据包的到达,当数据包到达后则直接通过sendto发送一个消息给上线客户端。

#include <winsock.h>
#include <iostream>

#pragma comment(lib, "wsock32.lib")
#define PORT  9999
#define GROUP "225.1.2.3"

using namespace std;

int main(int argc, char *argv[])
{
  WSADATA wsaData;
  struct sockaddr_in addr;
  int fd;
  struct ip_mreq mreq;

  // 初始化套接字
  if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
  {
    std::cout << "初始化失败" << std::endl;
    return 0;
  }

  // 创建套接字 SOCK_DGRAM 采用UDP
  if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
  {
    std::cout << "套接字创建失败" << std::endl;
    return 0;
  }

  // 设置套接字为组播模式
  u_int yes = 1;
  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0)
  {
    std::cout << "设置组播模式失败" << std::endl;
    return 0;
  }

  memset(&addr, 0, sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = htonl(INADDR_ANY);
  addr.sin_port = htons(PORT);

  // 绑定套接字
  if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
  {
    std::cout << "绑定失败" << std::endl;
    return 0;
  }

  // 设置组播模式中的组信息
  mreq.imr_multiaddr.s_addr = inet_addr(GROUP);
  mreq.imr_interface.s_addr = htonl(INADDR_ANY);

  // 设置组
  if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0)
  {
    int err = GetLastError();
    std::cout << "设置组失败: " << err << std::endl;
    return 0;
  }

  // 循环手法数据
  while (1)
  {
    char recv_buffer[4096];
    int addrlen = sizeof(addr);
    int nbytes;

    // 接收组播数据
    if ((nbytes = recvfrom(fd, recv_buffer, 4096, 0, (struct sockaddr *) &addr, (int *)&addrlen)) < 0)
    {
      std::cout << "接收数据包失败" << std::endl;
      return 0;
    }
    recv_buffer[nbytes] = '\0';
    std::cout << "接收组播数据包: " << recv_buffer << std::endl;

    // 发送组播数据包
    char send_buffer[4096] = "server mesage";
    sendto(fd, send_buffer, strlen(send_buffer), 0, (struct sockaddr *) &addr, sizeof(addr));
  }

  return 0;
}

14.5.2 客户端实现

在组播模式中客户端的修改部分很简单,仅仅只需通过socket(AF_INET, SOCK_DGRAM, 0)函数设置套接字为UDP模式,并填充组名即可,其他通信模式与UDP保持一致。

#include <winsock.h>
#include <iostream>

#pragma comment(lib, "wsock32.lib")
#define PORT  9999
#define GROUP "225.1.2.3"

using namespace std;

int main(int argc, char *argv[])
{
  WSADATA wsaData;
  struct sockaddr_in addr;
  int fd;

  // 初始化套接字
  if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
  {
    std::cout << "初始化失败" << std::endl;
    return 0;
  }

  // 创建套接字 SOCK_DGRAM 采用UDP
  if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
  {
    std::cout << "套接字创建失败" << std::endl;
    return 0;
  }

  // 设置组播模式组信息
  memset(&addr, 0, sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = inet_addr(GROUP);
  addr.sin_port = htons(PORT);

  // 循环
  while (1)
  {
    // 发送组播数据包
    char send_buffer[4096] = "Hello, World!";
    if (sendto(fd, send_buffer, strlen(send_buffer), 0, (struct sockaddr *) &addr, sizeof(addr)) < 0)
    {
      std::cout << "发送失败" << std::endl;
      return 0;
    }

    // 接收组播数据
    int addrlen = sizeof(addr);
    char recv_buffer[4096] = { 0 };
    recvfrom(fd, recv_buffer, 4096, 0, (struct sockaddr *) &addr, (int *)&addrlen);
    std::cout << "接收组播数据包: " << recv_buffer << std::endl;
    Sleep(1000);
  }
  return 0;
}

读者可自行编译上述代码,运行一个服务端并运行多个客户端即可观察组播收发情况,如下图所示;

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/22dcfd42.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

与14.5 Socket 应用组播通信相似的内容:

14.5 Socket 应用组播通信

组播通信是一种基于UDP协议的网络通信方式,它允许发送方将消息同时传递给多个接收方。在组播通信中,发送方和接收方都会加入一个共同的组播组,这个组播组对应一个特定的IP地址,所有加入该组播组的主机都能够接收到发送方发送的消息。组播通信可以有效地减少网络流量和网络负载,因为在传统的点对点通信方式下,每个消息都需要单独传输到每个接收方,而在组播通信中,每个消息只需要传输一次,就可以同时传递给多个接收方。

14.3 Socket 字符串分块传输

首先为什么要实行分块传输字符串,一般而言`Socket`套接字最长发送的字节数为`8192`字节,如果发送的字节超出了此范围则后续部分会被自动截断,此时将字符串进行分块传输将显得格外重要,分块传输的关键在于封装实现一个字符串切割函数,将特定缓冲区内的字串动态切割成一个个小的子块,当切割结束后会得到该数据块的个数,此时通过套接字将个数发送至服务端此时服务端在依次循环接收数据包直到接收完所有数据包之后

5.14 汇编语言:仿写Switch选择结构

选择结构,也称为switch语句,是计算机编程中的一种控制结构,用于根据表达式的值选择不同的执行路径。它允许程序根据表达式的值来决定执行哪个代码块,从而实现多分支选择逻辑。switch语句由一个表达式、多个case标签以及对应的代码块组成。程序会将表达式的值与每个case标签进行匹配,一旦找到匹配的case标签,程序将执行对应的代码块,并继续执行该代码块之后的代码,直到遇到break语句或者swi

.NET周报 【5月第2期 2023-05-14】

国内文章 XUnit数据共享与并行测试 https://www.cnblogs.com/podolski/p/17388602.html 在单元或者集成测试的过程中,需要测试的用例非常多,如果测试是一条一条过,那么需要花费不少的时间。从 V2 开始,默认情况下 XUnit 自动配置并行(参考资料),

OpenAI“杀疯了”,GPT–4o模型保姆级使用教程!一遍就会!

5月14日凌晨1点,OpenAI发布了名为GPT-4o 最新的大语言模型,再次引领了人工智能领域的又一创新浪潮,让整个行业都为之震动。 据OpenAI首席技术官穆里-穆拉提(Muri Murati)表示,GPT-4o是在继承GPT-4智能的基础上,对文本、视觉和音频功能进行了进一步改进,而且目前所有

[转帖]军备芯片14nm对比5nm,在战场上差距在哪里?

https://www.eet-china.com/mp/a207185.html 现在全球已经打响科技之战,每个国家都在力求让自己做到足够拔尖。美国商务部长就曾自曝家底说,美国制定两套战略应对在芯片上来自中国的竞争:一个是进攻战略,一个是防御战略,并且美国一直会坚持这种做法。 相关阅读: 面向AI

Docker Compose V2 安装 ClickHouse v20.6.8.5 经验分享

前言 ClickHouse 是一款开源的分布式列式数据库管理系统,专门设计用于高性能的大数据分析和查询。 目前项目中用到的一个场景是将mongo的数据同步到clickhouse,使用clickhouse做报表,后续也将分享同步和使用方案 使用 Docker Compose 部署单机版,小项目和自己测

3年Java阿里跳字节的面试心得总结

中厂->阿里->字节,成都->杭州->成都 系列文章目录和关于我 0.前言 笔者在不足两年经验的时候从成都一家金融科技中厂跳槽到杭州阿里淘天集团,又于今年5月份从杭州淘天跳槽到成都字节。自认为自己在面试这方面有一点心得,处于记录和分享的目的便有了此文,此文纯主观,也许对3年社招的同学有所帮助。 本文

研发三维GIS系统笔记/框架改造/智能指针重构框架-003

1. 使用智能指针重构系统 原有的系统都是裸指针,在跨模块与多线程中使用裸指针管理起来很麻烦,尤其是多任务系统中会出现野指针 1 class CELLTileTask :public CELLTask 2 { 3 public: 4 CELLQuadTree* _node; 5 TileId _ti

Python 潮流周刊#48:Python 3.14 的发布计划

本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章、教程、开源项目、软件工具、播客和视频、热门话题等内容。愿景:帮助所有读者精进 Python 技术,并增长职业和副业的收入。 本期分享了 12 篇文章,11 个开源项目,赠书 5 本《图解TCP/IP(第6版