C++ UDP绑定EADDRINUSE与SO_REUSEADDR
我有一个多线程Linux服务器,它有许多同时连接(每个线程2个连接),在响应客户机时必须绑定到公共IP地址。绑定UDP套接字时,我不时会遇到C++ UDP绑定EADDRINUSE与SO_REUSEADDR,c++,sockets,bind,C++,Sockets,Bind,我有一个多线程Linux服务器,它有许多同时连接(每个线程2个连接),在响应客户机时必须绑定到公共IP地址。绑定UDP套接字时,我不时会遇到EADDRINUSE错误,尽管我的日志表明套接字上次绑定到同一地址/端口并在套接字上调用shutdown()和close()是在30分钟之前 此外,我在这些UDP套接字(但不是自动绑定到本地地址/端口的套接字)上设置了SO_REUSEADDR、SO_REUSEPORT和IP_TRANSPARENT)。使用这些选项,即使有其他UDP套接字仍然绑定到本地地址上的
EADDRINUSE
错误,尽管我的日志表明套接字上次绑定到同一地址/端口并在套接字上调用shutdown()
和close()
是在30分钟之前
此外,我在这些UDP套接字(但不是自动绑定到本地地址/端口的套接字)上设置了SO_REUSEADDR
、SO_REUSEPORT
和IP_TRANSPARENT
)。使用这些选项,即使有其他UDP套接字仍然绑定到本地地址上的同一端口,绑定也不应该失败,因为SO\u REUSEADDR
,但它显然确实发生了
我找不到这种行为的解释
int makeUDPSocket(sockaddr_in *bindTo)
{
int sock;
if(-1 == (sock = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0)))
{
log("Could not make client UDP socket! Exiting.");
exit(18);
}
if(bindTo)
{
int enable = 1;
if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&enable, sizeof(enable)))
{
log("Could not set SO_REUSEADDR on UDP socket; errno=" + std::to_string(errno));
exit(2);
}
if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (const char*)&enable, sizeof(enable)))
{
log("Could not set SO_REUSEPORT on UDP socket; errno=" + std::to_string(errno));
exit(2);
}
if(-1 == setsockopt(sock, SOL_IP, IP_TRANSPARENT, (const char*)&enable, sizeof(enable)))
{
log("Could not set IP_TRANSPARENT on UDP socket; errno=" + std::to_string(errno));
exit(2);
}
if(-1 == bind(sock, (sockaddr*)bindTo, sizeof(sockaddr_in)))
{
log("Could not bind UDP socket. errno=" + std::to_string(errno) + ". Exiting.");
exit(19);
}
}
return sock;
}
void myfunc()
{
int sock0 = makeUDPSocket(NULL);
int sock1 = makeUDPSocket(&myPubAddr);
doStuff(sock0, sock1);
shutdown(sock0, SHUT_RDWR);
close(sock0);
shutdown(sock1, SHUT_RDWR);
close(sock1);
}
这是一个很长的解释,但你会学到很多。如果您跳到SO_REUSEADDR的部分,您的问题很可能是您没有为自动绑定的局部变量启用它;实际上,我最近读过这个答案,但据我所知,
因此_REUSEADDR
不需要在以前绑定的套接字上启用,以便将新套接字绑定到不同的地址和相同的端口。我刚刚发现,在Windows上,您可以在同一端口上有多个UDP套接字,例如,一个套接字用于发送线程,另一个套接字用于接收线程。但在Linux中,任何给定端口号上只能有一个套接字,这迫使发送线程和接收线程共享同一个套接字,