【问题标题】:Non-blocking socket loses data on Windows非阻塞套接字在 Windows 上丢失数据
【发布时间】:2015-05-08 08:07:32
【问题描述】:

我有一个支持所有连接客户端的非阻塞套接字服务器。它使用多线程并且可以使用 GCC 进行交叉编译。

它在 Linux 中完美运行(如我所愿),但是当我尝试在 Windows 中使用它时,当我通过它发送 70MB 的文件时,它会从文件中丢失大约 20MB。

所有套接字都是非阻塞的,所以对于接收/发送套接字调用,我没有检查/停止。它在一个循环中,它发送它接收到的东西,它有点像一个 Echo 服务器,但它在 Windows 中丢失了数据。我在 WSAStartup 中使用 Winsock 2.2。

怎么了?我怎样才能等待/刷新发送呼叫,但从不阻止接收呼叫? (如果这是问题)

代码片段: 我如何使它成为非阻塞的:

iMode = 1;
ioctlsocket(sock1,FIONBIO, &iMode);
ioctlsocket(sock2,FIONBIO, &iMode);

我如何在两个套接字之间发送/接收:

for (;;)
{
    memset(buffer, 0, 8192);
    int count = recv(sock1, buffer, sizeof(buffer), 0);
    receiveResult = WSAGetLastError();
    if (receiveResult == WSAEWOULDBLOCK && count <= 0)
        continue;
    if (count <= 0)
    {
        closesocket(sock1);
        closesocket(sock2);
        return;
    }
    if (count > 0)
    {
        int retval = send(sock2, buffer, count, 0);
    }

}

【问题讨论】:

  • 如果sendrecv 是非阻塞的,并且你正在接收到你正在发送的同一个缓冲区,会发生什么?那么同步呢?
  • 所以你认为问题是当我用缓冲区调用 send 时,它不会复制缓冲区并且在发送之前,数据被另一个 recv 调用覆盖?
  • 这可能不是问题所在。否则你会从 memset 得到很多 0。 send 应该足够聪明,可以有一个内部缓冲区。
  • 而且你没有检查之前的数据是否已经发送完毕。
  • @ehang,没错!我从来没有得到零。我只是在 75-80 MB 的文件中丢失了 20MB

标签: c++ c sockets gcc


【解决方案1】:
int count = recv(sock1, buffer, sizeof(buffer), 0);
receiveResult = WSAGetLastError();
if (receiveResult == WSAEWOULDBLOCK && count <= 0)

当调用recv()send() 时,WSAGetLastError() 将仅在返回 -1 (SOCKET_ERROR) 时返回一个有意义的值,但是当返回 0 时您也会检查它。当返回 >= 0 时,它们不会为 WSAGetLastError() 设置错误代码。您需要将这些条件分开。

另外,仅仅因为你已经读取了 X 个字节,并不能保证你一次可以发送 X 个字节,所以你需要检查send() 是否有WSAEWOULDBLOCK,直到你没有更多数据发送。

试试这样的:

bool keepLooping = true;
do
{
    int count = recv(sock1, buffer, sizeof(buffer), 0);
    if (count > 0)
    {
        // data received...

        char *p = buffer;
        do
        {
            int retval = send(sock2, p, count, 0);
            if (retval > 0)
            {
                p += retval;
                count -= retval;
            }
            else if (retval == 0)
            {
                // peer disconnected...
                keepLooping = false;
            }
            else if (WSAGetLastError() != WSAEWOULDBLOCK)
            {
                // a real error occurred...
                keepLooping = false;
            }
            else
            {
                // peer is not ready to receive...
                // optionally use select() to wait here until it is...
            }
        }
        while ((count > 0) && (keepLooping));
    }
    else if (count == 0)
    {
        // peer disconnected...
        keepLooping = false;
    }
    else if (WSAGetLastError() != WSAEWOULDBLOCK)
    {
        // a real error occurred...
        keepLooping = false;
    }
    else
    {
        // no data is available for reading...
        // optionally use select() to wait here until it is...
    }
}
while (keepLooping);

closesocket(sock1);
closesocket(sock2);
return;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-31
    • 2013-10-15
    • 1970-01-01
    • 2019-07-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多