Ale*_*x B 5 c sockets winapi tcp winsock
我正在将客户端 TCP套接字绑定到特定的本地端口.为了处理在插座保持在局势TIME_WAIT状态一段时间后,我用setsockopt()同SO_REUSEADDR一个插座上.
它可以在Linux上运行,但在Windows WSAEADDRINUSE上不起作用,connect()当前一个连接仍然存在时,我可以随叫随到TIME_WAIT.
MSDN并不完全清楚客户端套接字会发生什么:
[...]对于需要将多个套接字绑定到同一端口号的服务器应用程序,请考虑使用
setsockopt(SO_REUSEADDR).客户端应用程序通常不需要在所有连接上调用bind-connect自动选择未使用的端口.[...]
我该如何避免这种情况?
jwe*_*ich 10
使用时创建套接字时socket(),它只有一个类型和一个协议族.理想的是bind()它到本地地址:端口也是如此.
您提到的错误通常发生在最后一次连接到同一主机:端口没有正常关闭(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);
}
Run Code Online (Sandbox Code Playgroud)
更新:由于使用特定的本地端口是一个要求,考虑设置SO_LINGER与l_onoff=1和l_linger=0这样你的插座将无法阻止时close/ closesocket,它会忽略排队数据和(希望)关闭FD.作为最后的手段,您可以TIME_WAIT通过更改此注册表项的值来调整延迟(非常不鼓励!):
HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpTimedWaitDelay
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
41797 次 |
| 最近记录: |