客户端:
socket(), connect() and then
for (1 to 1024) {
write(1024 bytes)
}
exit(0);
服务器:
socket(), bind(), listen()
while (1) {
accept()
while((n = read()) {
if (n == -1) abort(); /* never happended */
total_read += n
}
close()
}
现在,客户端在NAT下在Mac上运行,服务器在我的VPS(国外)上运行
通常,它工作正常(客户端发送所有数据并退出和服务器recv所有数据)
然而,当客户端正在运行但突然网络被破坏几分钟(并重新获得)时,客户端将在很长一段时间后不会退出...我用控制+ C杀死它并再次运行它,服务器似乎不再读取数据(客户端仍在运行)
这是netstat显示的内容:
客户端:
tcp4 0 130312 192.168.1.254.58573 A.B.C.D.8888 ESTABLISHED
服务器:
tcp 0 0 A.B.C.D:8888 a.b.c.d:54566 ESTABLISHED 10970/a.out
tcp 102136 0 A.B.C.D:8888 a.b.c.d:60916 ESTABLISHED -
A.B.C.D是我的VPS地址 a.b.c.d是我的公共客户端地址
我的问题是:
1,为什么?
2,服务器重启后会正常工作,如何编写代码来摆脱它而不重启?
答案 0 :(得分:4)
在TCP中,除非您尝试在连接上发送内容,否则无法判断连接是否已失败。 TCP不会对连接执行主动监控(实际上,有可选的“keepalive”数据包,但这些数据通常在连接闲置几个小时后才会发送)。当你发送东西时,如果超时等待另一台机器返回确认,你最终会收到错误。但是,如果您只是在不发送数据的情况下阅读数据,则无法判断连接是否已失败 - 它看起来就像发件人没有任何要发送的内容。
您可以通过设计应用程序来解决此问题,以便客户端每隔N秒发送一次内容。然后在服务器中设置一个计时器,检测到你没有收到超过N秒的任何东西(你应该增加一些额外的时间来允许暂时的延迟)。
答案 1 :(得分:-1)
当网络崩溃时,发生的事情是你的客户端不断发送数据,并且在某些时候套接字发送缓冲区已满(我从你所显示的内容中了解到你发送1024字节,1024次,总共1MB)。发送缓冲区的默认值可能是16KB(肯定小于1MB)。然后,当客户端尝试写入时,它将永远被阻止。
顺便说一下,现在我回答你的问题我不知道最终是否经过多次TCP超时后,TCP放弃并关闭套接字,使套接字接口返回错误。我认为这没有发生...... :) - 所以,如果网络出现问题,连接失败,但写入和读取不会失败。在服务器端,服务器被禁止读取,因为它从未收到EOF。
解决方案:
在客户端使用非阻塞套接字,如果网络中断,在某些时候写入将返回错误EWOULDBLOCK。然后你会发现由于某种原因发送缓冲区已满。此时,您可以克隆连接并尝试再次连接。如果网络中断,您将收到错误。
在服务器端也使用非阻塞套接字和select()函数超时。经过几次超时后,您可能会认为新连接存在问题并将其关闭。