【问题标题】:TCP connection failureTCP连接失败
【发布时间】:2010-10-11 14:50:12
【问题描述】:

我在使用带有 connect() 和 read() 函数的简单 TCP 套接字时遇到问题。如果我先启动服务器,然后再启动客户端,这个程序就可以工作。但是,当我首先启动客户端时,它会继续尝试连接到服务器,然后当我启动服务器时,它会连接但随后的读取返回0字节。这表明服务器关闭了套接字,但调试语句不支持这一点。

我试图让客户端不断尝试连接到端口 6380 上的服务器,然后读取数据。如果连接丢失,客户端将尝试重新连接。我为套接字设置了 SO_REUSEADDR。我还有什么遗漏的吗?

服务器源代码

//***** SERVER *****
#include <iostream>
#include "SocketAdapter.h"
#include "SocketServer.h"
#include <errno.h>
#include <string.h>

unsigned char buffer[] = "123123123";

int main()
{
   SocketAdapter  socket;
   SocketServer   server(6380);

   server.Start();
   std::cout << "Wait for Connection" << std::endl;
   server.WaitForConnection(socket);
   std::cout << "Start to Send Data" << std::endl;

   while(1)
   {
      std::cout << "Sending Data   ";
      int bytesSent = socket.Send(buffer, 10);
      std::cout << "byteSent = " << bytesSent << std::endl;
      if (bytesSent == -1)
      {
         std::cout << "Errno (" << errno << ") - " << strerror(errno) << std::endl;
      }

      sleep(1);
   }//end while

   std::cout << "Ending Server" << std::endl;
   socket.Close();

   return 0;
}

客户端源代码

// ***** SIMPLE CLIENT ******
#include <iostream>
#include "SocketAdapter.h"
#include "SocketClient.h"
#include <string.h>
#include <errno.h>

int main()
{
   SocketAdapter  socket;
   SocketClient   client(6380, "127.0.0.1");

   unsigned char buffer[1024];


   while(1)
   {
      client.Start();

      //Loop till we connect to Server
      while( !client.Connect(socket) )
      {
         std::cout << "Trying to connect to server." << std::endl;
         sleep(1);
      }

      std::cout << "Connected to Server" << std::endl;

      //Read till we get a timeout
      while(1)
      {
         int bytesRead = socket.Recv(buffer, 10,2000);
         if (bytesRead != 10)
         {
            std::cout << "   Failed to Read" << std::endl;
            std::cout << "   bytesRead = " << bytesRead << std::endl;
            std::cout << "   Errno (" << errno << ") - "
                      << strerror(errno) << std::endl;
            break;
         }

         std::cout << "buffer = " << buffer << std::endl;
         usleep(250000);
      }

      std::cout << "Something went wrong, restart" << std::endl;
   }

   return 0;
}

服务器输出

./Server 
Wait for Connection
Start to Send Data
Sending Data   byteSent = 10

客户的输出

./Client 
Trying to connect to server.
Trying to connect to server.
Connected to Server
   Failed to Read
   bytesRead = 0
   Errno (107) - Transport endpoint is not connected
Something went wrong, restart
Close Socket
Close Socket File Descriptor
Connected to Server
Trying to Recv on a closed socket
Return Value = -1
Errno        = Connection reset by peer

   Failed to Read
   bytesRead = -3
   Errno (104) - Connection reset by peer
Something went wrong, restart
Close Socket
Close Socket File Descriptor
Socket cannot shutdown!
Return Value = -1
Errno        = Transport endpoint is not connected

Trying to connect to server.
Close Socket
Close Socket File Descriptor
Socket cannot shutdown!
Return Value = -1
Errno        = Transport endpoint is not connected

【问题讨论】:

  • 什么是 SocketAdapter.h 和 SocketServer.h?国产?
  • 我很惊讶服务器的输出没有一遍又一遍地喷出Sending Data byteSent = 10。为什么服务器上有 123MB 的缓冲区?客户端假设总是有 10 个字节要读取......即使在正常操作下也可能会有但不能保证。
  • 您可能会考虑使用Boost.Asio 而不是您自己开发的套接字包装器。
  • 是本土的。原因,服务器没有一遍又一遍地喷出 10 个字节,是客户端关闭了连接,服务器会尝试写入关闭套接字,它会生成一个未处理的 SIGPIPE 信号。

标签: c++ sockets tcp


【解决方案1】:

从套接字返回 0 个读取字节是完全合法的。这仅意味着您必须等待并重试。

例如看看这个read_data() function。它检查读取的字节数是否为&gt; 0,然后存储它们。它检查读取的字节数是否为&lt; 0,则为错误。

0 案例当然不是真正的成功,但也不是失败。再试一次。我没有很详细地分析你的代码,所以可能还有其他问题,但这是一个经常犯的重要错误。 (另外,那些未显示的类中有什么?)

您可以研究的是非阻塞套接字。另请参阅FAQ for how to tell if a socket is closed on the other end.,也许可以考虑detecting transfer completion explicitly by sending and end-of-file or marker

【讨论】:

  • 谢谢。就是这样。我假设 0 意味着失败,而另一端实际上关闭了套接字。但是,当我修改代码以继续并再次尝试读取时,它可以完美运行。
  • 这确实解决了我的问题,但是现在我无法弄清楚对方是否关闭了套接字。我认为从读取中接收 0 字节意味着另一端关闭了套接字。作为stackoverflow.com/questions/2416944/…
  • 读取的返回值 0 通常意味着套接字已断开连接(取决于您在套接字顶部使用的套接字框架)。您应该做的,尤其是在使用非阻塞套接字时,要等到套接字报告可读后,再实际进行读取。在连接的情况下,当连接成功时,socket会报告自己为可写的。
  • @Remy Lebeau,谢谢。 @Dennis Miller,请参阅我更新的帖子。在您阅读之前对套接字进行选择应该告诉它是否准备好阅读。
猜你喜欢
  • 2013-11-17
  • 1970-01-01
  • 2012-05-25
  • 1970-01-01
  • 2018-02-10
  • 1970-01-01
相关资源
最近更新 更多