SO_EXCLUSIVEADDRUSE和SO_REUSEADDR混淆

时间:2018-04-05 13:07:50

标签: sockets network-programming winsock winsock2

(在VS2017上运行,Win7 x64)

我对SO_REUSEADDRSO_EXCLUSIVEADDRUSE的观点感到困惑。是的,我读过MSDN documentation,但我显然没有得到它。

我在两个单独的进程中有以下简单代码。正如预期的那样,因为我在两个套接字上都启用了SO_REUSEADDR,所以第二个进程的绑定成功。 如果我没有在这些套接字中的任何一个上启用此功能,则第二个绑定将不会成功

#define PORT 5150
SOCKET sockListen;
if ((sockListen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
    printf("WSASocket() failed with error %d\n", WSAGetLastError());
    return 1;
}

int optval = 1;
if (setsockopt(sockListen, SOL_SOCKET, `SO_REUSEADDR`, (char*)&optval, sizeof(optval)) == -1)
    return -1;

SOCKADDR_IN InternetAddr;
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = inet_addr("10.15.20.97");
InternetAddr.sin_port = htons(PORT);

if (::bind(sockListen, (PSOCKADDR)&InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR)
{
    printf("bind() failed with error %d\n", WSAGetLastError());
    return 1;
}

所以不必为两个套接字启用SO_REUSEADDR使SO_EXCLUSIVEADDRUSE不必要 - 如果我不希望任何人强​​行绑定到我的端口,我只是不启用{{1}在那个过程中?

我能看到的唯一区别是,如果我在第一个进程中启用SO_REUSEADDR,那么在第二个进程中尝试绑定,第二个绑定将失败

a)SO_EXCLUSIVEADDRUSE如果我 在第二个过程中启用WSAEADDRINUSE

b)SO_REUSEADDR如果我在第二个过程中启用WSAEACCES

所以我尝试在第一个过程中同时启用SO_REUSEADDRSO_EXCLUSIVEADDRUSE,但发现我尝试的第二个过程失败了SO_REUSEADDR

另请注意,我已阅读this过去的问题,但所说的不是我所看到的:它说明了

  

具有SO_REUSEADDR的套接字始终可以绑定到完全相同的源   地址和端口作为已绑定的套接字,即使是另一个套接字   绑定时没有设置此选项

现在如果是这种情况,那么我绝对可以看到WSAEINVAL的需要。

我很确定我做错了什么但我看不到它;有人可以澄清吗?

1 个答案:

答案 0 :(得分:1)

如文档中所述,SO_EXCLUSIVEADDRUSE在Windows NT4 SP4上可用;之前有 SO_REUSEADDR。因此,两者都存在(也)历史原因。

我认为SO_REUSEADDR是意图来共享一个地址(这对于UDP多播非常有用。对于单播或TCP,由于bahaviour是非确定性的,所以它确实没有用。两个插座)。

SO_EXCLUSIVEADDRUSE是一个安全措施,以避免我的(服务器)应用程序的流量被以后绑定到同一IP /端口而被劫持/渲染无用。

在我看来,你需要 SO_REUSEADDR用于UDP多播,而你需要 SO_EXCLUSIVEADDRUSE作为服务器应用程序的安全措施。