坏网络的套接字编程

时间:2014-01-23 07:24:21

标签: sockets tcp network-programming

客户端:

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,服务器重启后会正常工作,如何编写代码来摆脱它而不重启?

2 个答案:

答案 0 :(得分:4)

在TCP中,除非您尝试在连接上发送内容,否则无法判断连接是否已失败。 TCP不会对连接执行主动监控(实际上,有可选的“keepalive”数据包,但这些数据通常在连接闲置几个小时后才会发送)。当你发送东西时,如果超时等待另一台机器返回确认,你最终会收到错误。但是,如果您只是在不发送数据的情况下阅读数据,则无法判断连接是否已失败 - 它看起来就像发件人没有任何要发送的内容。

您可以通过设计应用程序来解决此问题,以便客户端每隔N秒发送一次内容。然后在服务器中设置一个计时器,检测到你没有收到超过N秒的任何东西(你应该增加一些额外的时间来允许暂时的延迟)。

答案 1 :(得分:-1)

当网络崩溃时,发生的事情是你的客户端不断发送数据,并且在某些时候套接字发送缓冲区已满(我从你所显示的内容中了解到你发送1024字节,1024次,总共1MB)。发送缓冲区的默认值可能是16KB(肯定小于1MB)。然后,当客户端尝试写入时,它将永远被阻止。

顺便说一下,现在我回答你的问题我不知道最终是否经过多次TCP超时后,TCP放弃并关闭套接字,使套接字接口返回错误。我认为这没有发生...... :) - 所以,如果网络出现问题,连接失败,但写入和读取不会失败。

在服务器端,服务器被禁止读取,因为它从未收到EOF。

解决方案:

在客户端使用非阻塞套接字,如果网络中断,在某些时候写入将返回错误EWOULDBLOCK。然后你会发现由于某种原因发送缓冲区已满。此时,您可以克隆连接并尝试再次连接。如果网络中断,您将收到错误。

在服务器端也使用非阻塞套接字和select()函数超时。经过几次超时后,您可能会认为新连接存在问题并将其关闭。