7

我有一个非常烦人的问题,我在其他论坛上多次发现,但我找不到合适的解决方案。问题是 recv() 在连接的最后几个字节上返回 0。以下是一些背景信息。

  • 两个(客户端/服务器)应用程序都在同一台机器上运行。
  • 两个(客户端/服务器)套接字都是非阻塞的
  • 传输的数据大小为 53 字节。
  • 执行最后一次 send()/recv() 时,(客户端/服务器)都调用 shutdown 和 closesocket。
  • 我也试过 SO_LINGER 和 10 秒,也没有成功

我多次调用 send() (小块),从客户端传输了 53 个字节。服务器多次调用 recv()(4 字节请求)并读取 49 字节,然后返回 0(54 字节 - 49 字节,因此缺少 4 字节)。

MSDN 和一些论坛为非阻塞套接字编写:

  • recv() 在错误时肯定返回 < 0 并且设置了 errno / WSAGetLastError
  • 当对方关闭连接时,recv() 肯定会返回 = 0
  • 读取数据时,recv() 肯定返回 > 0

MSDN 还说:

使用带有 SD_SEND 或 SD_BOTH 的 closesocket 或关闭函数会导致在控制通道上发送 RELEASE 信号。由于 ATM 使用单独的信号和数据通道,RELEASE 信号可能会在最后一个数据到达其目的地之前到达远端,从而导致该数据丢失。一种可能的解决方案是在最后发送的数据与 ATM 套接字的 closesocket 或关闭函数调用之间设置足够的延迟。

这在 recv() 和 send() 的例子中被认为是:http: //msdn.microsoft.com/en-us/library/windows/desktop/ms740121 (v=vs.85).aspx

但是仍然没有成功,在收到 49 字节后,我仍然在 10% 的连接中得到一些中断,90% 的连接成功。有任何想法吗?谢谢。

4

3 回答 3

16

recv()仅当您请求 0 字节缓冲区或其他对等方已正常断开连接时才返回 0。如果您没有收到您期望的所有数据,那么您一开始就没有正确读取数据。请使用您的实际代码更新您的问题。

于 2012-05-10T01:42:25.263 回答
-1

我的猜测是,您并没有真正发送您认为正在发送的所有数据。查看:

终极 SO_LINGER 页面

于 2013-06-20T13:40:26.080 回答
-1
  • 当对方关闭连接时,recv() 肯定会返回 = 0

这并不完全正确,在下面使用非阻塞winsock2 tcp的代码中,当没有数据可用时,select返回1,recv返回0,WSAGetLastError()也是如此。

fd_set test = {1, socket};
const timeval timeout = {0, 0};
if (!::select(0, &test, nullptr, nullptr, &timeout)) return 0;
int done = ::recv(socket, buffer, 1, 0);

即使在另一端呼叫后,这种情况仍在继续:

::shutdown(socket, SD_BOTH);
::closesocket(socket);

然后结束。通信按预期工作,只是 ::recv 似乎被“破坏”了。

于 2020-06-17T10:03:51.977 回答