1

我正在为文件传输应用程序开发服务器。文件从安卓手机发送到我的服务器。

当文件大小较小时,它可以顺利运行。但是当文件很大(>2MB)时,服务器不会接收到整个数据包。

int recv(
  _In_   SOCKET s,
  _Out_  char *buf,
  _In_   int len,
  _In_   int flags
);

len函数中的值最初recv设置为20000,当我将其更改为 时8000,它开始工作。

令人惊讶的是,这只发生在Release mode in Visual Studio.

我使用wireshark 从我的移动设备中捕获日志。当服务器运行在调试模式时,手机会发送所有数据,但是当服务器运行在发布模式时,手机不会发送全部数据。(这是 len 的值设置为 的时候20000)。

但是,如果我通过基于 PC 的客户端发送大文件(客户端与服务器在同一台机器上),则值len可以保持在 20000。

有没有人遇到过这样的问题?这种行为的原因是什么?

注意:我正在使用 Visual Studio 在 Windows 上进行开发。

4

2 回答 2

4

len参数指定要读取的recv最大字节数。无法保证在recv准确读取此数量之前会阻塞;它可能会在读取任何较小数量的字节后返回。实际读取的数据量在返回值中注明。

recv如果要读取设定的字节数,则需要自己重复调用

int read_exact(SOCKET s, char* buf, int len)
{
    int remaining = len;
    do {
        int ret = recv(s, buf, remaining, 0);
        if (ret == 0) {
            break;
        }
        if (ret != SOCKET_ERROR ) {
            remaining -= ret;
            buf += ret;
        }
    } while (ret != SOCKET_ERROR && remaining > 0);
    return (ret==SOCKET_ERROR? SOCKET_ERROR : len - remaining);
}
于 2013-07-30T14:35:27.973 回答
1

recvsendlen参数都不是一个精确值,它只是一个提示,您可以最大程度地存储多少数据(对于 recv )或您要发送多少,每个函数返回一个错误或处理的字节数可能小于您的要求,忽略这种情况将导致随机错误,因为服务器没有完全发送它或者客户端没有收到正确的数量。

最安全的方法是每次发送一个标头,这将确保您知道您将要接收的数据量,在您期望该结构的客户端上,然后是数据。因为在这种情况下,您确切知道将发送/接收多少数据,您可以依赖它并继续调用函数,直到它们失败或最终执行您想要的操作(发送所有数据或接收所有数据)。

也永远不要尝试一次发送太大的块,因为它会填满winsock内部缓冲区,所以函数将返回这是合理的,因为它无法处理您的请求,因为它需要先发送数据或者没有更多空间了收到更多。

于 2013-10-14T19:41:53.323 回答