linux系统下多网卡UDP组播通信

linux系统下UDP组播指定网卡通信

linux系统下多网卡UDP通信时出现指定网卡发送数据失败的问题,需注意一下问题:

  1. 关闭系统防火墙
  2. 组播网关设置
  3. 指定需要发送数据的IP
    此程序只实现了多网卡同时接收数据和指定网卡发送数据的功能,未作将网卡A数据收到之后从网卡B转发出去操作,此部分逻辑功能需要再次添加实现。

实现环境

在这里插入图片描述

接收端代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define GROUP_IP "224.0.1.0"

int main(int argc, char const *argv[])
{
    /* code */
    int serv_sock;
    struct sockaddr_in my_addr,client_addr;

    // 1. 创建通信的套接字
    serv_sock = socket(AF_INET, SOCK_DGRAM, 0);
    if(serv_sock == -1)
    {
        perror("socket error");
        exit(0);
    }
  

    //设置组播属性
    struct ip_mreq mreq;    //组播结构体
    /* use setsockopt() to request that the kernel join a multicast group */    
    mreq.imr_multiaddr.s_addr=inet_addr(GROUP_IP);     //组播组的ip地址  
    mreq.imr_interface.s_addr=htonl(INADDR_ANY);       //加入的客户端主机的ip地址  INADDR_ANY为0.0.0.0,泛指本机,表示本机所有的ip.

    inet_pton(AF_INET, GROUP_IP, &mreq.imr_multiaddr);
    inet_pton(AF_INET, "192.168.4.29", &mreq.imr_interface);
    //客户端只有在加入多播组后才能接受多播组的数据
    setsockopt(serv_sock,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char *)&mreq,sizeof(mreq));

    //绑定本机地址
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(9999);    // 端口号
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);  // INADDR_ANY 任意网卡
    if( bind(serv_sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == -1 )
    {
        printf("udp server bind error\n");
        return -1;
    }
     printf("udp bind success [%s] [%d]\n",GROUP_IP,my_addr.sin_port);

    //接收数据
    char recvBuf[1024]={0};
    socklen_t addrlen = sizeof(struct sockaddr_in);
    char *ip = NULL;
    int port = 0;
    int ret = 0;

    while (1)
    {
        memset(recvBuf,0,sizeof(recvBuf));
        ret = recvfrom(serv_sock,recvBuf,sizeof(recvBuf),0,(struct sockaddr *)&client_addr,&addrlen);

        ip = inet_ntoa(client_addr.sin_addr);
        port = ntohs(client_addr.sin_port);
 
        printf("[%s][%d]buf:%s ret:%d\n",ip,port,recvBuf,ret);

    }
    
    close(serv_sock);

    return 0;
}

客户端发送端代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define GROUP_IP "224.0.1.0"
#define GROUP_PORT  9999

int main(int argc, char const *argv[])
{
    int serv_sock;
    struct sockaddr_in my_addr,zubo_addr;

    // 1. 创建通信的套接字
    serv_sock = socket(AF_INET, SOCK_DGRAM, 0);
    if(serv_sock == -1)
    {
        perror("socket error");
        exit(0);
    }

    /*
    将本地socket添加到多播组中,注意,此处针对struct ip_mreq结构体需要填充两个成员,
    成员ipmr.imr_interface.s_addr的值指定的是将要发送的网卡的ip地址,
    成员impr.imr_multiaddr指定的是组播地址;
    如果指定为INADDR_ANY则系统会绑定一个默认网卡的具体ip(根据默认网关选择),则会出现特定网卡可以发送和接收组播信息,另一网卡不可以。
    即指定INADDR_ANY并不能把所有网卡都添加多播组中,必须明确指定对应网卡ip才可以。*/
    struct in_addr addr = {0};
    addr.s_addr=inet_addr("192.168.4.29"); //指定需要发送的网卡
    struct ip_mreq ipmr;
    ipmr.imr_interface.s_addr =  addr.s_addr;
    ipmr.imr_multiaddr.s_addr = inet_addr(GROUP_IP);
    setsockopt(serv_sock,IPPROTO_IP,IP_ADD_MEMBERSHIP,(const char*)&ipmr,sizeof(ipmr));
    setsockopt(serv_sock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&addr, sizeof(addr));

    //给组播地址发送数据
    zubo_addr.sin_family = AF_INET;
    zubo_addr.sin_port = htons(GROUP_PORT);    // 端口号
    zubo_addr.sin_addr.s_addr = inet_addr(GROUP_IP);  // IP地址
    // 发送组播消息, 需要使用组播地址, 和设置组播属性使用的组播地址一致就可以
    inet_pton(AF_INET, GROUP_IP, &zubo_addr.sin_addr.s_addr);

    char sendBuf[1024] = {0};
    int num = 0;
    int ret = 0;

    while (1)
    {
        memset(sendBuf,0,sizeof(sendBuf));
        sprintf(sendBuf, "###### hello, world! ######%d\n", num++);
        // 往组播地址发送数据
        ret = sendto(serv_sock, sendBuf, strlen(sendBuf)+1, 0, (struct sockaddr*)&zubo_addr, sizeof(struct sockaddr_in));
        printf("发送的组播的数据: %s\n", sendBuf);
        memset(sendBuf,0,sizeof(sendBuf));
        sleep(2);

    }
    
    close(serv_sock);

    return 0;
}

实现效果

在这里插入图片描述

执行 recvUDP接收 程序
在这里插入图片描述

执行sendUDP从千兆网卡发出去,下图为PC2(192.168.4.29)linux系统接收到kylin发送过来的数据

执行 sendUDP从万兆网卡发送出去,下图为PC2(192.168.1.98)windows系统UDP测试工具接收到的数据

在这里插入图片描述

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值