我知道在* NIX环境中使用带有UDP的SO_REUSEADDR,其行为类似于多播,其中绑定到同一端口的多个客户端可以同时侦听和接收广播数据报。这也是Windows上的行为吗?
答案 0 :(得分:4)
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;
}