Windows 中的 SO_REUSEADDR 和 UDP 行为

发布于 2024-10-19 04:03:59 字数 97 浏览 1 评论 0原文

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

I'm aware that using SO_REUSEADDR with UDP in a *NIX environment, behaves like a multicast, where multiple clients bound to the same port can listen and receive broadcast datagrams simultaneously. Is this the behavior on Windows as well?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

沒落の蓅哖 2024-10-26 04:03:59

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;
}

Multiple UDP sockets on Windows bound to the same port will all receive broadcast packets together.

Here's a demo program you can build for windows and Linux with GCC and test with Netcat as mentioned. In both systems, only one socket (either A or B) receives each datagram when a unicast address is used as the target. If a broadcast address is used then both sockets will receive the message.

/* 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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文