【问题标题】:winsock recv() duplicates/missing datawinsock recv() 重复/丢失数据
【发布时间】:2013-02-16 23:11:10
【问题描述】:

我正在编写一个简单的服务器/客户端程序来将文件从客户端发送到服务器。 我正在使用winsock2。我将每次发送数据的容量限制为 5000。

客户端(发送):

int iResult = 0;
int totalBytesSent = 0;

while (length > 0){
    iResult = send( _connectSocket, data, MAX_TRANSIT_SIZE, 0 ); // MAX_TRANSIT_SIZE is 5000
    if (iResult == SOCKET_ERROR) {
        printf("send failed with error: %d\n", WSAGetLastError());
        return closeSocket();
    }
    totalBytesSent += iResult;
    length -= iResult;
    //cout << "Data sent (" << iResult << " Bytes)" << endl;
}
cout << "Total Bytes Sent: (" << totalBytesSent << ")" << endl;

return 0;

在服务器端 (recv):

    // Receive and send data
char recvbuf[MAX_DATA_SIZE];

int iResult = 0;
int totalBytesRead = 0;

// Receive until the peer shuts down the connection

do {
    totalBytesRead += iResult;
    iResult = recv(_clientSocket, recvbuf, MAX_DATA_SIZE, 0);

    if (iResult > 0) {
        //printf("RECEIVED DATA\n");
        //printf("Bytes received: %d\n", iResult);

    } else if (iResult == 0)
        printf("Connection closing...\n");
    else {
        printf("recv failed: %d\n", WSAGetLastError());
        closesocket(_clientSocket);
        WSACleanup();
        return 1;
    }

} while (iResult > 0);

cout << "Total Bytes Received: (" << totalBytesRead << ")" << endl;

问题:

在运行客户端和服务器并发送文件后,它确实显示发送/接收的正确数据大小(当然是以字节为单位的文件大小),但输出文件不同,当我用一些文本打开它时编辑器(记事本++)我可以清楚地看到输出文件包含较少的数据(但文件->属性显示相同的文件大小)并且一些数据是重复的。

我的问题:

revc() 是如何工作的?如果它在许多调用中接收数据,它会在缓冲区中累积数据吗? (在我的情况下:recvbuf)还是重写缓冲区? 据我所知,它确实会累积,所以我的代码是正确的??

谢谢。

【问题讨论】:

    标签: c++ sockets winsock recv


    【解决方案1】:

    您的代码中有几个问题。

    客户端:

    send( _connectSocket, data, MAX_TRANSIT_SIZE, 0 );
    
    • 在这里,您永远不会更新 data 以说明已发送的字节数,因此每次调用 send 时它都会一次又一次地发送相同的数据(MAX_TRANSIT_SIZE 缓冲区的第一个 MAX_TRANSIT_SIZE 字节)。假设data 是指向任何字节类型(uint8_t、char、...)的指针,一个快速修复方法是:

      send( _connectSocket, data + totalBytesSent, MAX_TRANSIT_SIZE, 0 );

    • 您还应该限制您发送的数据大小,因为除非length 最初是MAX_TRANSIT_SIZE 的倍数,否则当您到达数据末尾时会出现缓冲区溢出:

      send( _connectSocket, data + totalBytesSent, std::min(length, MAX_TRANSIT_SIZE), 0 );


    服务器端:

    recv(_clientSocket, recvbuf, MAX_DATA_SIZE, 0);
    
    • 就像send 一样,recv 没有“我已经在那个缓冲区中收到了什么”的概念。因此,每次调用recv 时,它都会将接收到的新数据放在缓冲区的开头,覆盖旧数据。这可能是也可能不是您想要的,这很难说,因为您没有向我们展示您如何使用该缓冲区。您可能希望使用与我刚刚解释的发送缓冲区相同的方法来管理接收缓冲区。

    【讨论】:

    • 感谢您提供的信息丰富的回答。我将尝试解释我如何处理传输: 在客户端:我将文件(二进制流)读入 char 数组,然后将其发送到服务器。在服务器端:我从客户端接收代表文件的 char 数组,并将其写入磁盘。
    【解决方案2】:

    我没有看到你在 recvbuf 中的什么地方写的。每次调用 recv 时,它都会覆盖 recvbuf 中已有的内容。因此,如果您有注释掉的“接收数据”打印,您应该复制要保留在缓冲区之外的数据。

    【讨论】:

    • 你确定每次都覆盖??因为在 VS2010 调试器中我可以看到它包含相同的数据(前几个字节是带有空终止符的字符串,因此调试器显示直到 \0)并且我在代码的其他地方使用缓冲区:fileData * fData = FileTransfer: :deserializeFileData(recvbuf);
    猜你喜欢
    • 2019-08-16
    • 1970-01-01
    • 1970-01-01
    • 2014-03-11
    • 2012-07-05
    • 1970-01-01
    • 1970-01-01
    • 2013-07-31
    • 2012-04-21
    相关资源
    最近更新 更多