【问题标题】:SO_REUSEADDR and UDP behavior in WindowsWindows 中的 SO_REUSEADDR 和 UDP 行为
【发布时间】:2020-04-22 18:05:36
【问题描述】:

我知道在 *NIX 环境中使用带有 UDP 的 SO_REUSEADDR 的行为类似于多播,其中绑定到同一端口的多个客户端可以同时侦听和接收广播数据报。这也是 Windows 上的行为吗?

【问题讨论】:

    标签: windows sockets udp


    【解决方案1】:

    Windows 上绑定到同一个端口的多个 UDP 套接字都会一起接收广播数据包。

    这是一个演示程序,您可以使用 GCC 为 windows 和 Linux 构建并使用 Netcat 进行测试,如上所述。在这两个系统中,当使用单播地址作为目标时,只有一个套接字(A 或 B)接收每个数据报。如果使用广播地址,那么两个套接字都会收到消息。

    /* Tested on linux and windows 7.
     * On windows use mingw-gcc:
     *    gcc -Wall -g -o udplisten udplisten.c -lws2_32
     * Test with:
     *    echo hello | netcat -u machinename 9898 (unicast)
     *    echo hello | netcat -u 172.16.255.255 9898 (broadcast)
     */
    #ifdef WIN32
    #include <winsock2.h>
    #include <ws2tcpip.h>
    #else
    #include <sys/select.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #define SOCKET int
    #define INVALID_SOCKET -1
    #endif
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    
    #undef max
    #define max(x,y) ((x) > (y) ? (x) : (y))
    
    static void
    die(const char *str)
    {
        perror(str);
        exit(1);
    }
    
    static SOCKET
    mksocket(struct sockaddr_in *addr)
    {
        SOCKET sock = INVALID_SOCKET;
        int opt = 1;
        if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
            die("socket");
        if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt)) < 0)
            die("setsockopt");
        if (bind(sock, (struct sockaddr *)addr, sizeof(struct sockaddr_in)) < 0)
            die("bind");
        return sock;
    }
    
    static void
    process(SOCKET sock, const char *label)
    {
        char buffer[8192];
        struct sockaddr_in caddr;
        socklen_t caddr_size = sizeof(caddr);
        memset(&caddr, 0, caddr_size);
        int count = recvfrom(sock, buffer, sizeof(buffer), 0,
                             (struct sockaddr *)&caddr, &caddr_size);
        if (count < 0) die(label);
        printf("%s %d '", label, count);
        fwrite(buffer, 1, count, stdout);
        printf("'\n");
    }
    
    int
    main(int argc, char *argv[])
    {
        struct sockaddr_in addr;
        SOCKET socka = INVALID_SOCKET, sockb = INVALID_SOCKET;
        fd_set read_set;
    #ifdef WIN32
        WSADATA wsaData;
        if (WSAStartup(MAKEWORD(2,2), &wsaData))
            return -1;
    #endif
        addr.sin_family = AF_INET;
        addr.sin_port = htons(9898);
        addr.sin_addr.s_addr = INADDR_ANY;
    
        socka = mksocket(&addr);
        sockb = mksocket(&addr);
    
        for (;;) {
            FD_ZERO(&read_set);
            FD_SET(socka, &read_set);
            FD_SET(sockb, &read_set);
            if (select(max(socka,sockb)+1, &read_set, NULL, NULL, NULL) < 0)
                die("select");
            if (FD_ISSET(socka, &read_set))
                process(socka, "A");
            if (FD_ISSET(sockb, &read_set))
                process(sockb, "B");
        }
        return 0;
    }
    

    【讨论】:

    • 组播或广播数据包将在所有套接字上多路复用,单播数据包只会发送到第一个打开的套接字。
    • @Steve-o 我说的是广播数据包。广播数据包是否也在 Windows 中被多路复用?
    • 我贴的程序可以用来测试这个。您可以使用 netcat -u 172.16.255.255 9898 使用 netcat 发送到广播地址。当我尝试这个时,我的 linux 机器和 Windows 机器都会在每个套接字(A 和 B)上接收数据包。您可能应该编辑问题以指定您在此处谈论广播数据包。
    猜你喜欢
    • 2015-12-16
    • 1970-01-01
    • 2013-03-20
    • 2023-03-03
    • 1970-01-01
    • 2018-11-17
    • 2011-01-09
    • 2012-09-14
    • 1970-01-01
    相关资源
    最近更新 更多