在旧版本的 Mac OS X 中,通配符绑定(bind)的工作方式如下所述:
Multicast Addresses
The meaning of SO_REUSEADDR changes for multicast addresses as it allows multiple sockets to be bound to exactly the same combination of source multicast address and port. In other words, for multicast addresses SO_REUSEADDR behaves exactly as SO_REUSEPORT for unicast addresses. Actually the code treats SO_REUSEADDR and SO_REUSEPORT identically for multicast addresses, that means you could say that SO_REUSEADDR implies SO_REUSEPORT for all multicast addresses and the other way round.
和
MacOS X
At its very core, MacOS X is simply a BSD-style UNIX, based on a rather late fork of the BSD code, which was even synchronized with FreeBSD 5 for the Mac OS 10.3 release. That's why MacOS X offers the same options as BSD and they also behave the same way as in BSD.
但是在 10.10.5 中,我在测试网络库时发现了一个变化。
即使设置了 SO_REUSEADDR,两个未绑定(bind)(通配符)UDP 套接字也不能再共享同一端口 (errno=EADDRINUSE)。 两者都必须设置 SO_REUSEPORT,这对我来说是个谜。
它可以用这个简单的测试代码重现:
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
int main() {
for(int p = 0; p < 4; ++p) {
printf("Flags set: ");
if(p&1) printf("SO_REUSEADDR ");
if(p&2) printf("SO_REUSEPORT");
printf("\n");
int handles[2];
bool success = true;
for(int i = 0; i < sizeof(handles)/sizeof(int); ++i) {
handles[i] = socket(AF_INET, SOCK_DGRAM, 0);
int flag = 1;
if((p&1) && setsockopt(handles[i], SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) == -1) {
printf("Setsockopt %d, SO_REUSEADDR failed with errno\n", i, errno);
success = false;
break;
}
if((p&2) && setsockopt(handles[i], SOL_SOCKET, SO_REUSEPORT, &flag, sizeof(flag)) == -1) {
printf("Setsockopt %d, SO_REUSEPORT failed with errno\n", i, errno);
success = false;
break;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = 2000; // does not matter as long as it is currently free
addr.sin_addr.s_addr = 0; // wildcard address
if(bind(handles[i], (struct sockaddr*)&addr, sizeof(addr)) == -1) {
printf("Bind %d failed with errno %d\n", i, errno);
success = false;
break;
}
}
if(success)
printf("Alright\n");
for(int i = 0; i < sizeof(handles)/sizeof(int); ++i)
close(handles[i]);
printf("\n");
}
return 0;
}
哪些输出:
Flags set:
Bind 1 failed with errno 48
Flags set: SO_REUSEADDR
Bind 1 failed with errno 48
Flags set: SO_REUSEPORT
Alright
Flags set: SO_REUSEADDR SO_REUSEPORT
Alright
最佳答案
In older versions of Mac OS X, wildcard binding works like described here:
block 引用>Multicast Addresses
…您引用的描述适用于多播地址。您的测试代码不使用 multicast address 。因此,适用不同的描述(来自同一来源):
SO_REUSEPORT
SO_REUSEPORT
is what most people would expectSO_REUSEADDR
to be. Basically,SO_REUSEPORT
allows you to bind an arbitrary number of sockets to exactly the same source address and port as long as all prior bound sockets also hadSO_REUSEPORT
set before they were bound. …您的测试代码完全证实了这一点。
关于macos - SO_REUSEADDR 和 SO_REUSEPORT 的行为改变了吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32661091/