Windows中的SO_REUSEADDR和UDP行为

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

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