TCP套接字recv指示成功发送后“意外”断开连接

时间:2016-08-03 21:25:17

标签: c sockets tcp

我在阻塞模式下有一个TCP套接字用于请求/响应协议的客户端。有时我发现如果套接字未使用一两分钟send调用成功并指示发送的所有字节,但后面的recv返回零,表示关闭。我在Windows和Linux客户端都看到了这一点。

服务器人告诉我,如果他们收到了数据,他们总会在关机前发送一些响应,但如果服务器资源不足,他们可能会关闭一个尚未收到任何内容的套接字。

我看到的是服务器在我没有使用时关闭连接的原因,那么send为什么会成功呢?

在这种情况下,自动检测此问题的正确方法是什么,以便在新连接上重新发送请求,但请记住,如果服务器实际收到某些请求两次可能会产生意外影响?

//not full code (buffer management, wrapper functions, etc...)
//no special flags/options are being set, just socket then connect
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
connect(sock, addr, addrlen);
//some time later after many requests/responses, normally if was inactive for a minute
//sending about 50 bytes for requests, never actually seen it loop, or return 0
while (more_to_send) check(send(sock, buffer, len, 0));
//the very first recv returns 0, never seen it happen part way through a response (few KB to a couple of MB)
while (response_not_complete) check(recv(sock, buffer, 4096, 0));

2 个答案:

答案 0 :(得分:1)

  • 如果您未从服务器获得申请的申请确认,请重新发送。
  • 将您的交易设计为idempotent,以便重新发送它们不会造成不良影响。

答案 1 :(得分:1)

  

我所看到的是服务器关闭的指示   我没有使用它的连接

  

,然后为什么发送然后成功?

send()的成功只告诉你传递给send()的一些(或全部)数据已成功复制到内核缓冲区中,从现在开始,操作系统有责任尝试将这些字节传递给远程对等体。

特别是,表示这些字节实际已经通过网络(尚未)或已被服务器成功接收。

  

正确的方法是什么,自动检测到这样的   在这种情况下,请求在新连接上重新发送,但承载   请注意,如果服务器实际上收到了两次请求,可以   有意想不到的影响吗?

正如EJP建议的那样,最好的方法是设计你的通信协议,以便两次发送相同的请求与发送一次不同。一种方法是为您发送的每条消息添加一个唯一的ID,并向服务器添加一些逻辑,这样如果它收到的ID与已经处理的ID相同,则会丢弃该消息。消息作为重复。

让服务器发回对每条消息的明确响应(以便您可以确定您的消息已通过并已处理)可能有所帮助,但当然您必须开始担心收到消息的情况并且处理了然后TCP连接中断了,然后响应可以传递回给你,等等。

你可以做的另一件事(如果你还没有这样做)是监视TCP套接字的状态(通过select(),poll()或类似),以便立即通知你的程序(当远程对等体关闭其套接字的末尾时,通过套接字select() - 作为准备读取。这样你就可以在尝试发送()命令之前很好地处理关闭的TCP连接,而不是之后只发现它,这应该是一个不太尴尬的情况,因为在在这种情况下,没有关于命令是否“通过”的问题。