我尝试使用Winsock制作文件下载器,但我意识到,如果Internet连接速度较慢,客户端会收到一些不需要的数据以及服务器发送的数据。
所以我做了一个简单的测试:
我从服务器发送的数字从1到30000:

char* buf = (char*)malloc(BUFLEN);
for( int i = 0;i < 30000;++i ){
     ZeroMemory(buf, BUFLEN);
     itoa(i+1, buf, 10);
     send(current_client, buf, BUFLEN, 0);
}
free(buf);

客户端接收并保存它们:
char *buf = (char*)malloc(DEFAULT_BUFLEN);
ofstream out;
out.open(filename, ios::binary);
for( int i = 0;i < 30000;++i ){
     ZeroMemory(buf, DEFAULT_BUFLEN);
             recv(ConnectSocket, buf, DEFAULT_BUFLEN, 0);
             out.write(buf, DEFAULT_BUFLEN);
             out << endl;
}
out.close();
free(buf);

我希望在文件中看到类似的内容:
1个
2
3
4
...
30000
但是取而代之的是传输了一些额外的包含“/ 0”的数据包,文件看起来像这样:
1个
2
3

4
5

6
...
2600
如果我尝试跳过“/ 0”数据包,则来自服务器的数据也将被跳过,如下所示:
1个
2
3
4
5
6
9 ...
2600
我究竟做错了什么 ?

最佳答案

recv()告诉您实际接收了多少个字节。您会忽略输出整个缓冲区的那个值,即使它没有完全填满也是如此。服务器端也是如此-发送更多数据然后进行格式化。

您也没有考虑到send()recv()可以发送/接收的字节数少于您请求的字节数。

尝试以下方法:

bool sendraw(SOCKET socket, void *buf, int buflen)
{
    unsigned char *p = (unsigned char*) buf;
    while (buflen > 0)
    {
        int sent = send(socket, p, buflen, 0);
        if (sent < 1) return false;
        p += sent;
        buflen -= sent;
    }
    return true;
}

for( int i = 0; i < 30000;++i )
{
    int j = htonl(i+1);
    if (!sendraw(current_client, &j, sizeof(int)))
        break;
}


bool recvraw(SOCKET socket, void *buf, int buflen)
{
    unsigned char *p = (unsigned char*) buf;
    while (buflen > 0)
    {
        int received = recv(socket, p, buflen, 0);
        if (received < 1) return false;
        p += received;
        buflen -= received;
    }
    return true;
}

ofstream out;
out.open(filename, ios::binary);
for( int i = 0; i < 30000;++i )
{
    int j;
    if (!recvraw(ConnectSocket, &j, sizeof(int)))
        break;
    out << ntohl(j) << endl;
}
out.close();

关于c++ - Winsock收到额外的数据,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11764687/

10-13 06:50
查看更多