【问题标题】:Weird win sock bug on non blocking recv()非阻塞recv()上的奇怪win sock错误
【发布时间】:2020-12-19 19:19:47
【问题描述】:

这是我的非重叠套接字的接收文件函数。

            HANDLE recvfile = CreateFile(fileinfo[0], FILE_APPEND_DATA, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
            if (recvfile == INVALID_HANDLE_VALUE) {
                sockprintf(sockfd, "[Error Creating File] : %ld", GetLastError());
            }
            else {
                memset(recvbuf, '\0', BUFFER); // Clear main buffer
                int total = 0; // Total bytes received
                // set_blocking_mode(sockfd, FALSE);
                do{ // IF Total is equal to expected bytes. Break the loop, And stop receiving.
                    fsize = recv(sockfd, recvbuf, BUFFER, 0); // Receive file
                    if (fsize == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)
                    {
                        connected = FALSE;
                        printf("[X] Connection interrupted while receiving file %s for %s size.", fileinfo[0], fileinfo[1]);
                    }
                    write = WriteFile(recvfile, recvbuf, fsize, &dwBytesWritten, NULL); // Write file data to file
                    total += fsize; // Add number of bytes received to total.
                } while(total != expected);
                // set_blocking_mode(sockfd, TRUE);
                if (write == FALSE)
                {
                    sockprintf(sockfd, "[Error Writing file %s of %s size] Error : %ld.", fileinfo[0], fileinfo[1], GetLastError());
                }
                else {
                    sockprintf(sockfd, "\n[ Received File : %s ]\n[ File Size : %s bytes ]\n[ Bytes written : %ld ]\n", fileinfo[0], fileinfo[1], dwBytesWritten);
                }
                CloseHandle(recvfile);
            }

这很好用!文件传输几乎是即时的,没有错误或损坏的缓冲区。 我在 Visual Studio 2019 上。问题是,当我编译可执行文件并将其移动到测试虚拟机时。程序崩溃。在 Windows 10 和 Windows 7 上测试。

在 do while 循环中发生崩溃。该程序不会摆脱它。我尝试使用 msvc(最新)以及 mingw-w64 和 tdm gcc 进行编译。错误是一样的。 该代码仅适用于我自己的机器,它不适用于任何其他机器。

【问题讨论】:

  • Err... 为什么要设置非阻塞?如果返回 WSAEWOULDBLOCK 错误会发生什么?
  • } while(total != expected); 似乎雄心勃勃,但没有显示它们的更新位置。
  • @MartinJames 更正,我忘了补充,非阻塞设置为仅测试。我应该更新问题。
  • 程序为什么打不出来?你应该能找到。
  • @coderman 也许你应该在每次循环运行时打印出 fsize 和 total 和 expected,然后你就可以看到为什么循环还在运行?

标签: c windows winsock


【解决方案1】:

您需要检查的不仅仅是 WSAECONNRESET。几乎每个错误(非阻塞中的“将阻塞”除外)都是致命的,并表明应该中止套接字。不要忘记,如果远程端优雅地结束,recv 可以并且将返回 0

整个循环:

            do{ // IF Total is equal to expected bytes. Break the loop, And stop receiving.
                fsize = recv(sockfd, recvbuf, BUFFER, 0); // Receive file
                if (fsize == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)
                {
                    connected = FALSE;
                    printf("[X] Connection interrupted while receiving file %s for %s size.", fileinfo[0], fileinfo[1]);
                }
                write = WriteFile(recvfile, recvbuf, fsize, &dwBytesWritten, NULL); // Write file data to file
                total += fsize; // Add number of bytes received to total.
            } while(total != expected);

应该是:

            do{ 
                fsize = recv(sockfd, recvbuf, BUFFER, 0); // Receive file
                if (fsize == SOCKET_ERROR) {

                    int err = WSAGetLastError();
                    if (err == WSAEWOULDBLOCK) {

                        // ISSUE SELECT CALL HERE TO WAIT FOR MORE DATA

                    }
                    else {
                        // FATAL ERROR - abort
                        break;
                    }

                }
                else if (fsize == 0) {
                    break;  // remote connection terminated cleanly.
                }
                else {
                    write = WriteFile(recvfile, recvbuf, fsize, &dwBytesWritten, NULL);
                    total += fsize;
                }
            } while(total != expected);

【讨论】:

  • 这里真的有合理的期望吗,或者在使用int expected = atoi(fileinfo[1]); 输入expected 的OP 代码中,totalexpected 可能完全对齐?即==?
  • @ryyker 我希望完全匹配,假设文件信息已完全正确传输.....
  • @MartinJames - 好的,我会再阅读一下这个主题。当涉及到任何类似于tcp/ip 基于套接字的数据传输时,设置任何== 似乎总是有风险的。事实证明,这里的问题确实是 fileinfo[] 在 OP 的 新机器 上进行评估之前没有正确初始化。
【解决方案2】:

我已经解决了这个问题,看来问题是我自己的无知,服务器端提供文件信息的速度太快了,因此,fileinfo[] 混淆了。因此循环不会中断。仍然不明白为什么它在开发机器上工作。无论如何,正如预期的那样,问题不在我在此问题中发布的代码中。谢谢你们! 解决方案是在睡眠时间较短的情况下发送数据。 :)

【讨论】:

  • 我仍然坚持我的回答。您需要更加勤奋地检查错误。否则,当您调用 WriteFile 时,您的 fsize-1 将被强制转换为 unsigned 并且会发生奇怪的事情。
  • 这不是答案。你需要一个真正的协议,即使每次 recv 调用读取一个字节也能正常工作。
猜你喜欢
  • 1970-01-01
  • 2015-06-18
  • 1970-01-01
  • 2010-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-13
相关资源
最近更新 更多