SO_EXCLUSIVEADDRUSE 和 SO_REUSEADDR 混淆

SO_EXCLUSIVEADDRUSE and SO_REUSEADDR confusion

(运行 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 - 如果我不想让任何人强行绑定到我的端口,我只是不启用 SO_REUSEADDR在那个过程中?

我能看到的唯一区别是,如果我在第一个进程中启用 SO_EXCLUSIVEADDRUSE,然后在第二个进程中尝试绑定,则第二个绑定将失败并显示

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

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

所以我尝试在第一个过程中同时启用 SO_EXCLUSIVEADDRUSESO_REUSEADDR,但发现我第二次尝试的任何一个都失败了 WSAEINVAL

另请注意,我已阅读 this 过去的问题,但其中所说的与我所看到的不同:它指出

A socket with SO_REUSEADDR can always bind to exactly the same source address and port as an already bound socket, even if the other socket did not have this option set when it was bound

现在如果是这样的话,那么我肯定可以看到 SO_EXCLUSIVEADDRUSE 的必要性。

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

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

我认为 SO_REUSEADDR 是 意图 共享地址(这仅对 UDP 多播非常有用。对于单播或 TCP 它确实没有用由于两个套接字的行为都是 non-deterministic。

SO_EXCLUSIVEADDRUSE 是一种 安全措施 以避免我的(服务器)应用程序的流量被劫持/被稍后绑定到相同 IP/port.

据我所知,您需要 SO_REUSEADDR 用于 UDP 多猫,并且您 需要 SO_EXCLUSIVEADDRUSE 作为服务器应用程序的安全措施。