You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux 4.1内核下修改设备IP后UDP组播出现sendto网络不可达问题

问题描述

基于Linux 4.1内核的项目,静态IP环境下实现UDP组播:

  • 当设备IP为10.13.204.100时,sendto发送组播数据正常;
  • 修改IP为10.13.204.101或同网段其他IP后,调用close(socket_desc)关闭套接字并重新调用udp_init初始化,仍报错sendto: network unreachable。

附原UDP初始化代码:

int udp_init()
{
    char multicastTTL = 10;
    // Create UDP socket:
    memset(&socket_desc, 0, sizeof(socket_desc));
    socket_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (socket_desc < 0)
    {
        perror("socket");
        return 1;
    }
    udp_socket_fd = socket_desc;
    printf("udp_socket_fd=>%d\nsocket_desc==>%d\n", udp_socket_fd, socket_desc);

    /* Set the TTL (time to live/hop count) for the send */
    // if (setsockopt(socket_desc, IPPROTO_IP, IP_MULTICAST_TTL, &multicastTTL, sizeof(multicastTTL)) < 0)
    if (setsockopt(socket_desc, SOL_SOCKET, SO_REUSEADDR, &multicastTTL, sizeof(multicastTTL)) < 0)
    {
        perror("setsockopt");
        exit(1);
    }

    memset(&server_addr, 0, sizeof(server_addr)); /* Zero out structure */
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(EXAMPLE_GROUP); // INADDR_ANY;
    server_addr.sin_port = htons(EXAMPLE_PORT);             // htons(udp_port);

    // bind to receive address
    //
    if (bind(socket_desc, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        perror("bind");
        printf("line %s-->%s:%d\n", __FILE__, __FUNCTION__, __LINE__);
        return 1;
    }
}

问题分析与解决方案

核心问题点

  1. setsockopt参数错误:
    误将SO_REUSEADDR的选项值设为multicastTTL(char类型的10),但SO_REUSEADDR要求传入int类型的1,此错误会导致套接字选项失效,引发后续网络异常。

  2. 绑定了错误的地址:
    代码中将套接字绑定到组播地址EXAMPLE_GROUP,而非INADDR_ANY或本地网卡IP。当网卡IP变更后,绑定的组播地址无法关联到新网卡,内核找不到合适的路由出口。

  3. 未指定组播出口IP:
    网卡IP变更后,内核无法自动选择新IP作为组播数据包的源IP,需显式设置IP_MULTICAST_IF指定出口网卡IP。

修正后的代码

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

#define EXAMPLE_GROUP "224.0.0.1" // 替换为你的组播地址
#define EXAMPLE_PORT 12345        // 替换为你的组播端口

int udp_socket_fd = -1;
struct sockaddr_in server_addr;

int udp_init(const char *local_ip) {
    int reuse_addr = 1;
    char multicastTTL = 10;
    struct in_addr if_addr;

    // 清理旧套接字
    if (udp_socket_fd != -1) {
        close(udp_socket_fd);
        udp_socket_fd = -1;
    }

    // 创建UDP套接字
    int socket_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (socket_desc < 0) {
        perror("socket");
        return 1;
    }
    udp_socket_fd = socket_desc;

    // 设置SO_REUSEADDR(正确参数)
    if (setsockopt(socket_desc, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)) < 0) {
        perror("setsockopt SO_REUSEADDR");
        close(socket_desc);
        return 1;
    }

    // 设置组播TTL(恢复原注释的正确代码)
    if (setsockopt(socket_desc, IPPROTO_IP, IP_MULTICAST_TTL, &multicastTTL, sizeof(multicastTTL)) < 0) {
        perror("setsockopt IP_MULTICAST_TTL");
        close(socket_desc);
        return 1;
    }

    // 指定组播出口IP(关键:传入当前网卡的静态IP)
    if (inet_aton(local_ip, &if_addr) == 0) {
        perror("inet_aton");
        close(socket_desc);
        return 1;
    }
    if (setsockopt(socket_desc, IPPROTO_IP, IP_MULTICAST_IF, &if_addr, sizeof(if_addr)) < 0) {
        perror("setsockopt IP_MULTICAST_IF");
        close(socket_desc);
        return 1;
    }

    // 绑定到INADDR_ANY,适配任意网卡IP
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(EXAMPLE_PORT);

    if (bind(socket_desc, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("bind");
        close(socket_desc);
        return 1;
    }

    return 0;
}

额外注意事项

  • 每次修改网卡IP后,调用udp_init时必须传入新的静态IP,确保IP_MULTICAST_IF指向正确出口。
  • 检查组播路由:执行ip route show确认224.0.0.0/4段路由指向当前网卡,若缺失可手动添加:ip route add 224.0.0.0/4 dev eth0(替换eth0为你的网卡名)。
  • 关闭套接字后,确保udp_socket_fd被重置为-1,避免使用无效文件描述符。

内容的提问来源于stack exchange,提问作者Rajesh D

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 18:05:32