谷动谷力

 找回密码
 立即注册
查看: 1740|回复: 0
打印 上一主题 下一主题
收起左侧

Linux网络编程——UDP组播编程

[复制链接]
跳转到指定楼层
楼主
发表于 2023-8-4 16:20:59 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 sunsili 于 2023-8-4 16:23 编辑

Linux网络编程——UDP组播编程


一,基础概念
数据报文在网络中的点对点传输方式通常有以下三种:
单播(Unicast): 数据报文从一个发送端到一个接收端的通信方式。
组播(Multicast): 数据报文从一个发送端到多个接收端的通信方式。
广播(broadcast): 数据报文从一个发送端到所有接收端的通信方式。
组播的实现需要设置组播地址
在IPv4中组播的地址范围是:224.0.0.0到239.255.255.255。

二,组播的具体实现过程
发送端:
step.01:新建一个socket套接字1用于往组播发送数据报文。
step.02:在sockaddr_in结构体中初始化组播的端口号。
step.03:设置IP_MULTICAST_LOOP等组播选项。
step.04:使用IP_MULTICAST_IF选项来定义组播接口。
step.05:调用sendto()接口往组播中发送数据报文。

接收端:
step.01:新建一个socket套接字2用于从组播接收数据报文。
step.02:设置SO_REUSEADDR选项以允许多个接收端去接收同一端口的数据报文。
step.03:调用bind()接口让套接字2绑定到组播指定的端口号。
step.04:使用IP_ADD_MEMBERSHIP选项,加入指定的组播。
step.05:调用read()接口从组播中接收数据报文。

三,组播属性设置
使用类型为SOCK_DGRAM的套接字,基于UDP协议来实现组播传输过程。
使用setsockopt()接口来设置与组播相关的属性。
setsockopt接口规范:
#include <sys/socket.h>
int setsockopt(int socket,
               int level,
               int option_name,
               const void *option_value,
               socklen_t option_len);

#返回值:成功后返回0,否则返回-1并设置对应的错误码
setsockopt()接口可以为组播设置以下属性:
IP_ADD_MEMBERSHIP:加入指定的组播。
IP_DROP_MEMBERSHIP:退出指定的组播。
IP_MULTICAST_IF:设置组播中发送数据报文的接口。
IP_MULTICAST_TTL:设置组播中数据报文的生存时间(TTL)。
IP_MULTICAST_LOOP:设置组播中数据报文的副本是否回传。
四,完整代码实现
Demo1——C++代码实现
发送端:#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>

struct in_addr localInterface;
struct sockaddr_in groupSock;
int sd;
char databuf[1024] = "Multicast Data MSG!";
int datalen = sizeof(databuf);

int main (int argc, char *argv[])
{
  /*
   * Create a datagram socket on which to send.
   */
  sd = socket(AF_INET, SOCK_DGRAM, 0);
  if (sd < 0) {
    perror("opening datagram socket");
    exit(1);
  }

  /*
   * Initialize the group sockaddr structure with a
   * group address of 225.1.1.1 and port 5555.
   */
  memset((char *) &groupSock, 0, sizeof(groupSock));
  groupSock.sin_family = AF_INET;
  groupSock.sin_addr.s_addr = inet_addr("225.1.1.1");
  groupSock.sin_port = htons(5555);

  /*
   * Disable loopback so you do not receive your own datagrams.
   */
  {
    char loopch=0;


    if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP,
                   (char *)&loopch, sizeof(loopch)) < 0) {
      perror("setting IP_MULTICAST_LOOP:");
      close(sd);
      exit(1);
    }
  }

  /*
   * Set local interface for outbound multicast datagrams.
   */
  localInterface.s_addr = inet_addr("127.0.0.1");
  if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF,
                 (char *)&localInterface,
                 sizeof(localInterface)) < 0) {
    perror("setting local interface");
    exit(1);
  }

  /*
   * Send a message to the multicast group specified by the
   * groupSock sockaddr structure.
   */
  if (sendto(sd, databuf, datalen, 0,
             (struct sockaddr*)&groupSock,
             sizeof(groupSock)) < 0)
  {
    perror("sending datagram message");
  }
  else
  {
    printf("sending datagram message ok! \n");
    printf("The message send to multicast server is: \"%s\"\n", databuf);
  }
}
接收端:#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>

struct sockaddr_in localSock;
struct ip_mreq group;
int sd;
char databuf[1024];
int datalen = sizeof(databuf);

int main (int argc, char *argv[])
{
  /*
   * Create a datagram socket on which to receive.
   */
  sd = socket(AF_INET, SOCK_DGRAM, 0);
  if (sd < 0) {
    perror("opening datagram socket");
    exit(1);
  }

  /*
   * Enable SO_REUSEADDR to allow multiple instances of this
   * application to receive copies of the multicast datagrams.
   */
  {
    int reuse=1;
    if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR,
                   (char *)&reuse, sizeof(reuse)) < 0) {
      perror("setting SO_REUSEADDR");
      close(sd);
      exit(1);
    }
  }

  /*
   * Bind to the proper port number with the IP address
   * specified as INADDR_ANY.
   */
  memset((char *) &localSock, 0, sizeof(localSock));
  localSock.sin_family = AF_INET;
  localSock.sin_port = htons(5555);;
  localSock.sin_addr.s_addr  = INADDR_ANY;

  if (bind(sd, (struct sockaddr*)&localSock, sizeof(localSock))) {
    perror("binding datagram socket");
    close(sd);
    exit(1);
  }

  /*
   * Join the multicast group 225.1.1.1 on the local 9.5.1.1
   */
  group.imr_multiaddr.s_addr = inet_addr("225.1.1.1");
  group.imr_interface.s_addr = inet_addr("127.0.0.1");
  if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                 (char *)&group, sizeof(group)) < 0) {
    perror("adding multicast group");
    close(sd);
    exit(1);
  }

  /*
   * Read from the socket.
   */
  datalen = sizeof(databuf);
  if (read(sd, databuf, datalen) < 0) {
    perror("reading datagram message");
    close(sd);
    exit(1);
  }
  else
  {
    printf("get datagram message ok! \n");
    printf("The message from multicast server is: \"%s\"\n", databuf);
  }
}
运行结果:发送端:sending datagram message ok!
The message send to multicast server is: "Multicast Data MSG!"
接收端:get datagram message ok!
The message from multicast server is: "Multicast Data MSG!"
Demo2——Python代码实现发送端:import socket
from time import sleep, time

MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)

while True:
    print "Multicast to group: %s\n" % MCAST_GRP
    data = 'Hello World: ' + repr(time()) + '\n'
    sock.sendto(data, (MCAST_GRP, MCAST_PORT))
    sleep(1)
接收端:
import socket
import struct

MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', MCAST_PORT))
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)

sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)

while True:
    print sock.recv(10240)
运行结果:发送端:Multicast to group: 224.1.1.1

Multicast to group: 224.1.1.1

Multicast to group: 224.1.1.1

Multicast to group: 224.1.1.1
接收端:Hello World: 1690308503.613114

Hello World: 1690308503.613114

Hello World: 1690308504.615013

Hello World: 1690308504.615013
五,参考阅读
https://www.ibm.com/docs/en/i/7.1?topic=designs-examples-using-multicasting-af-inet
https://os.mbed.com/handbook/Socket
https://subingwen.cn/linux/multicast/index.html
+10
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|深圳市光明谷科技有限公司|光明谷商城|Sunshine Silicon Corpporation ( 粤ICP备14060730号|Sitemap

GMT+8, 2024-12-27 18:18 , Processed in 0.092530 second(s), 44 queries .

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表