跳转至主要内容

以下STCP代码片段展示了我观察到的问题。它会在recv调用处阻塞,直到有数据可读取,随后处理接收到的数据并再次调用recv——该调用要么返回更多数据(或报错),要么再次阻塞。若发生错误,recv将返回-1,并将错误代码设置在errno变量中。您认为这段代码是否正确?

while (1)
   {
   cBytes = recv (socks1, buffer, BUFFERLEN, 0);
   if (cBytes == -1)
      {
      perror ("Unexpected error at recv");
      exit (errno);
      }
   else
      printf ("number of bytes received : %dn", cBytes);
   }

该代码假设远程对等方永远不会优雅地关闭连接。当远程对等方执行优雅关闭(即调用close或shutdown函数)时,recv会通过返回零字节向本地应用程序发出提示。后续对recv的调用将持续返回零字节。结果导致代码陷入无所作为的紧循环。例如:

接收字节数:8
接收字节数:57
接收字节数:16
接收字节数:1
接收字节数:1
接收字节数:0
接收字节数:0
接收字节数:0
接收字节数:0
接收字节数:0.
 . . . .

即使应用协议规定远程对等方永远不会优雅地关闭连接,你也无法保证连接永远不会被优雅关闭。远程应用程序可能存在缺陷,或者当应用进程终止时,远程TCP堆栈可能会执行优雅关闭。又或者,其他应用程序建立了连接,但在未收到预期响应时将其关闭。  安全审计(或恶意用户)执行端口扫描或抓取系统标识时,也可能执行优雅关闭。关键在于:你必须始终处理零字节的情况。

while (1)
   {
   cBytes = recv (socks1, buffer, BUFFERLEN, 0);
   if (cBytes <= 0)
      {
      if (cBytes < 0)
         {
         perror ("Unexpected error at recv");
         exit (errno);
         }
      else
         {
         printf ("received closen");
         close (socks1);
         exit (0);
         }
      }
   else
      printf ("number of bytes received : %dn", cBytes);
   }

接收字节数:28
接收字节数:2
接收字节数:58
接收关闭