windows - Windows 中的 SO_REUSEADDR 和 UDP 行为

标签 windows sockets udp

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

最佳答案

绑定(bind)到同一端口的 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;
}

关于windows - Windows 中的 SO_REUSEADDR 和 UDP 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5077887/

相关文章:

networking - 如何在 Rust 中广播 UDP 数据报并接收响应?

c# - 确定系统架构

windows - 为什么 Windows x64 调用约定不使用 XMM 寄存器来传递超过 4 个整数参数?

java - TCP 连接 Socket.getInputStream()

c - 如何将 udp 套接字绑定(bind)到单个单播地址

c - 服务器不接收来自客户端的数据

ruby - 为什么二进制文件在压缩时会损坏?

windows - 批处理文件 - 关闭由批处理文件进程打开的单独的 cmd 窗口

c++ - WSAENOBUFS 和 WSAEWOULDBLOCK 有什么区别?

sockets - 关于 UDP 服务器如何将响应发送回 UDP 客户端的困惑