参数:
网卡物理单网卡
掩码 255.255.0.0 → 网段:192.9.0.0/16
需要两个本地 IP:
IP1:192.9.2.100
IP2:192.9.10.1

情景:

我的软件需要两个ip的udp套接字
一个是192.9.2.100
一个是192.9.10.1
但子网掩码是255.255.0.0
但我的电脑是单网卡

关键点:两个 IP属于同一个大网段 192.9.0.0/16

不存在跨网关、路由冲突问题

不需要虚拟网卡、不需要 USB 网卡、不需要 VLAN。

最优解决方案:单网卡绑定多个 IP 地址(本机多 IP)

操作系统原生支持,零额外软件,Qt UDP Socket 完全兼容。

你在代码里创建两个 UDP 套接字,分别绑定两个本地 IP 即可:

QUdpSocket sock1, sock2;
sock1.bind(QHostAddress("192.9.2.100"), 端口);
sock2.bind(QHostAddress("192.9.10.1"), 端口);

Windows 配置步骤

  1. 网卡 → IPv4 属性 →【高级】
  2. IP 地址区域点击【添加】
    • 地址:192.9.2.100 掩码:255.255.0.0
    • 再点添加:192.9.10.1 掩码:255.255.0.0
  3. 网关只填写一个(不要填多个网关!同网段多网关会出诡异路由问题)

cmd 查看是否生效:ipconfig,网卡会列出两个 IPv4 地址

银河麒麟(Linux ARM)配置方案(两种任选)

方式 1:nmcli 命令(NetworkManager,图形系统推荐)

NetworkManagerClient

# 假设网卡名称 eth0,替换成你的网卡名(ip a查看)
nmcli connection modify eth0 ipv4.addresses "192.9.2.100/16,192.9.10.1/16"
nmcli connection modify eth0 ipv4.method manual
# 网关只设置一个,示例网关按需修改
nmcli connection modify eth0 ipv4.gateway "192.9.0.1"
nmcli connection up eth0

方式 2:ifupdown / 静态配置文件(无桌面服务器)

在 interfaces 配置额外地址(secondary 地址)

auto eth0
iface eth0 inet static
    address 192.9.2.100
    netmask 255.255.0.0
    gateway 192.9.0.1

iface eth0 inet static
    address 192.9.10.1
    netmask 255.255.0.0

重启网络生效。

验证:ip a 看到网卡上两个 inet 地址。

非常重要的坑(针对 UDP 通信)

  1. 同网卡多个 IP,收发 UDP 完全正常,socket 绑定指定 IP 可以区分源地址;
  2. 远端回复报文能不能正确送达,同 / 16 网段完全没问题,二层可达;
  3. ❌不要两个 IP 配置两个网关!同一个 / 16 网段只保留一条默认网关;
  4. 注意防火墙:两个 IP 的端口都要放行;
  5. Qt UDP 注意:不要 bind (0.0.0.0),必须显式绑定指定 IP,否则系统随机选用源 IP,无法区分两套链路。

补充:会不会出现什么异常?

很多人担心:单网卡两个 IP,会不会收到的包分不清属于哪个 socket?不会。当你 bind(指定IP) 之后:

  • 目标 IP=192.9.2.100 的报文 → 进入 sock1
  • 目标 IP=192.9.10.1 的报文 → 进入 sock2
  • Linux/Windows 协议栈原生区分,工业 UDP 场景大量这么用。

什么时候才需要虚拟网卡 / USB 网卡?

只有下面场景才需要额外硬件 / 虚拟网卡:

两个 IP 属于不同主网段(比如一个 192.9.x.x,一个 10.0.x.x,且需要两套独立网关);

你当前场景完全不需要!


我的套接字使用的是原生c代码 不是qt

原生 C socket 完全支持

关键点:创建两个 socket,调用bind()显式绑定各自本地 IP,不能绑定INADDR_ANY

C 原生 UDP 最简示例(Linux/Windows 通用思路,区分平台头文件)

Linux (银河麒麟 ARM)

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

#define PORT 8080

int main()
{
    int fd1, fd2;
    struct sockaddr_in addr_local1, addr_local2;

    // socket1 绑定 192.9.2.100
    fd1 = socket(AF_INET, SOCK_DGRAM, 0);
    memset(&addr_local1, 0, sizeof(addr_local1));
    addr_local1.sin_family = AF_INET;
    addr_local1.sin_port = htons(PORT);
    inet_pton(AF_INET, "192.9.2.100", &addr_local1.sin_addr);

    if (bind(fd1, (struct sockaddr *)&addr_local1, sizeof(addr_local1)) < 0)
    {
        perror("bind 192.9.2.100 failed");
        return -1;
    }

    // socket2 绑定 192.9.10.1
    fd2 = socket(AF_INET, SOCK_DGRAM, 0);
    memset(&addr_local2, 0, sizeof(addr_local2));
    addr_local2.sin_family = AF_INET;
    addr_local2.sin_port = htons(PORT);
    inet_pton(AF_INET, "192.9.10.1", &addr_local2.sin_addr);

    if (bind(fd2, (struct sockaddr *)&addr_local2, sizeof(addr_local2)) < 0)
    {
        perror("bind 192.9.10.1 failed");
        close(fd1);
        return -1;
    }

    printf("两个UDP socket绑定成功\n");
    printf("sock1: 192.9.2.100:%d\n", PORT);
    printf("sock2: 192.9.10.1:%d\n", PORT);

    // 后续可以用select/poll/epoll同时监听两个fd收发数据

    close(fd1);
    close(fd2);
    return 0;
}

必须重视的几个底层坑(C 开发极易踩)

不要绑定 INADDR_ANY (0.0.0.0)           

如果 bind 0.0.0.0,发送 UDP 时系统会自动选源 IP,你无法控制使用 192.9.2.100 还是 192.9.10.1;

✅强制:每个 socket 绑定独立本地 IP。

端口能否相同?

Linux:允许,不同本地 IP,相同端口可以 bind 成功(上面代码就是同端口)

Windows:默认情况下,同端口、不同 IP 也支持;极少数老旧系统需要开启SO_REUSEADDR


Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐