簡體   English   中英

Winsock收到額外的數據

[英]Winsock receiving extra data

我嘗試使用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

6
...
2600
如果我嘗試跳過“ / 0”數據包,則來自服務器的數據也會被這樣跳過:
1
2
3
4

6
9 <-7和8丟失
...
2600
我究竟做錯了什么 ?

recv手冊頁中:

對於面向連接的套接字(例如,類型為SOCK_STREAM),調用recv將返回當前可用的盡可能多的數據-達到指定緩沖區的大小。

這意味着recv可能會給您不完整的數據包。 如果數據包上有固定長度或終結符,則需要在附加到緩沖區的循環中調用recv ,直到接收到全部。 但是,這帶來了另一個問題,第二次調用recv可能會給您最后一個數據包的其余部分,也可能給您另一個數據包的一部分。

在您的情況下,發送方的發送速度可能快於接收方的接收速度,在這種情況下, recv將阻塞(如果套接字正在阻塞)或返回錯誤(如果套接字未阻塞)。 您必須檢查recv返回的值才能知道它是什么。 如果套接字是非阻塞的,則recv將返回SOCKET_ERROR (即-1 ),而WSAGetLastError將返回WSAEWOULDBLOCK

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(); 

我找出了問題所在。
就像Joachim和Remy所說的那樣,有時客戶端不會收到整個緩沖區,因此我對代碼做了一些修改:
從服務器端:

             sent = 0;
             while( sent != BUFLEN ){
                    sent += send(current_client, (buf+sent), BUFLEN-sent, 0);
             }

和客戶:

             recvd = 0;  
             while( recvd != DEFAULT_BUFLEN ){  
                    recvd += recv(ConnectSocket, (buf+recvd), DEFAULT_BUFLEN-recvd, 0);  
             }  

而且我知道緩沖區沒有完全填滿,通常我將二進制數據作為char *發送,而不僅僅是整數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM