Winsock recv()复制/丢失数据

winsock recv() duplicates/missing data

本文关键字:数据 复制 recv Winsock      更新时间:2023-10-16

我正在编写一个简单的服务器/客户端程序,将文件从客户端发送到服务器。我正在使用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: %dn", 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 DATAn");
        //printf("Bytes received: %dn", iResult);
    } else if (iResult == 0)
        printf("Connection closing...n");
    else {
        printf("recv failed: %dn", WSAGetLastError());
        closesocket(_clientSocket);
        WSACleanup();
        return 1;
    }
} while (iResult > 0);
cout << "Total Bytes Received: (" << totalBytesRead << ")" << endl;

问题:

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

我的问题:

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

谢谢。

你的代码中有几个问题。

客户端:

send( _connectSocket, data, MAX_TRANSIT_SIZE, 0 );
  • 这里你永远不会更新data来考虑已经发送的字节,所以每次你调用send时,它都会一次又一次地发送相同的数据(data缓冲区的第一个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时,它只是将接收到的新数据放在缓冲区的开头,覆盖旧数据。这可能是也可能不是你想要的,这很难判断,因为你没有向我们展示你是如何使用缓冲的。你可能想使用与我刚才解释的发送缓冲区相同的方法来管理你的接收缓冲区。

我看不出你写在哪里了。每次调用recv时,它都会覆盖recvbuf中已经存在的内容。因此,在您有注释掉的"RECEIVED DATA"打印的地方,您应该复制您想要保留在缓冲区之外的数据。