使用Winsock将客户端TCP套接字绑定到特定本地端口时,SO_REUSEADDR没有任何影响

我将客户端 TCP套接字绑定到特定的本地端口。 为了处理套接字保持TIME_WAIT状态一段时间的情况,我在套接字上使用带有SO_REUSEADDR setsockopt()

它适用于Linux,但不适用于Windows,当前一个连接仍在TIME_WAIT时,我在connect()调用时得到WSAEADDRINUSE

MSDN并不完全清楚客户端套接字会发生什么:

[…]对于需要将多个套接字绑定到同一端口号的服务器应用程序,请考虑使用setsockoptSO_REUSEADDR )。 客户端应用程序通常不需要在所有连接上调用bind-connect自动选择未使用的端口。 […]

我该如何避免这种情况?

使用socket()创建套接字时,它只有一个类型和一个协议族。 理想的是bind()bind()到本地地址:port也是如此。

您提到的错误通常发生在与同一主机的最后一次连接时:端口没有正常关闭(FIN / ACK FIN / ACK)。 在这些情况下,套接字在一段时间内保持TIME_WAIT状态(OS依赖,但可调)。

然后会发生什么情况是当你尝试connect()到同一个主机和相同的端口时,它使用默认套接字的名称/地址/端口/等,但这个组合已经被你的僵尸套接字使用了。 为避免这种情况,您可以通过在创建套接字后调用bind()来更改本地地址:用于建立连接的端口,提供填充了本地地址和随机端口的sockaddr结构。

 int main() { int ret, fd; struct sockaddr_in sa_dst; struct sockaddr_in sa_loc; char buffer[1024] = "GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n"; fd = socket(AF_INET, SOCK_STREAM, 0); // Local memset(&sa_loc, 0, sizeof(struct sockaddr_in)); sa_loc.sin_family = AF_INET; sa_loc.sin_port = htons(LOCAL_RANDOM_PORT); sa_loc.sin_addr.s_addr = inet_addr(LOCAL_IP_ADDRESS); ret = bind(fd, (struct sockaddr *)&sa_loc, sizeof(struct sockaddr)); assert(ret != -1); // Remote memset(&sa_dst, 0, sizeof(struct sockaddr_in)); sa_dst.sin_family = AF_INET; sa_dst.sin_port = htons(80); sa_dst.sin_addr.s_addr = inet_addr("64.233.163.104"); // google :) ret = connect(fd, (struct sockaddr *)&sa_dst, sizeof(struct sockaddr)); assert(ret != -1); send(fd, buffer, strlen(buffer), 0); recv(fd, buffer, sizeof(buffer), 0); printf("%s\r\n", buffer); } 

更新 :由于需要使用特定的本地端口,考虑设置SO_LINGERl_onoff=1l_linger=0这样你的套接字不会在close / close阻塞,它只会忽略排队的数据并(希望)关闭fd。 作为最后的手段,您可以通过更改此注册表项的值来调整TIME_WAIT延迟(非常不鼓励!):

 HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpTimedWaitDelay 

您没有指定正在运行的Windows平台,这可能会影响您正在运行的安全主体(即您是管理员?)…

这可能会有所帮助: http : //blogs.msdn.com/wndp/archive/2005/08/03/Anthony-Jones.aspx

小心绑定本地端口NOT使用环回地址“127.0.0.1”,否则您将获得连接超时。 最好不要填充sa_loc.sin_addr.s_addr – 这很好用。