2011-09-10 26 views
2

我遇到了Winsock2包裝類(客戶端 - 服務器)的問題,經過無數個小時的搔癢 - 我的頭在混亂,我決定,如果我問你的意見。C++,Send()函數發送額外的字節

更具體地說,問題是每次使用我的Send()函數時,客戶端和服務器(並不總是)會發送一個或兩個額外的字節!

例如,我使用SendBytes(「Hello」),Recv函數在字符數組的末尾使用'•'或其他隨機字符返回「Hello•」。

//main.cpp (Client) 
    #include "Socket.h" 

    int main() 
    { 
     NetworkService::Client cService = NetworkService::Client(); 
     int res = cService.Initialize("127.0.0.1","20248"); 
     if(res == 0){ 
      int local = cService.SendBytes("Hello!"); 
      printf("Bytes Sent: %ld\n", local); 
      cService.Shutdown(); 

      char* temp = cService.Recv(); 
      printf("String Recieved: %s - Size: %d",temp,strlen(temp)); 
      printf("\nSTRLEN: %d",strlen("X5")); 
     } 
     else{ 
      cService.Clean(); 
     } 
     cService.Close(); 
     while(!kbhit()); 
     return 0; 
    } 

當然,服務器發送字符串 「X5」,並在客戶端打印strlens ...

//The result with "X5" as the dummy text: 
String Recieved: X5? - Size: 3 //Notice the extra '?' character 
STRLEN: 2 

發送//收到功能

int NetworkService::Client::SendBytes(char* lData){ 
      int local = send(ConnectSocket, lData, (int)strlen(lData), 0); 
      if (local == SOCKET_ERROR) { 
       Close(); 
       return WSAGetLastError(); 
      } 
      return local; 
    } 

    char* NetworkService::Client::Recv(){ 
     recv(ConnectSocket, recvbuf , recvbuflen, 0); 
     return recvbuf; 
    } 

幫助,將不勝感激^ _ ^。

+2

你沒有發送字符串中的終止NUL字節。 –

+0

非常感謝您回答如此之快!繼承人的事情,我在字符串的末尾添加了'\ 0',但它沒有做任何事情。我仍然得到隨機插入。 – Christian

+1

@christian:通過字符串文字,你已經有一個隱式的\ 0。爲了發送它,你需要在send()調用中調整size參數。將其從strlen(lData)更改爲strlen(lData)+1以包含結尾的\ 0。如果您仍然不確定爲什麼這是必要的,請務必查看[strlen()](http://cplusplus.com/reference/clibrary/cstring/strlen/)函數。 – ComicSansMS

回答

1

你不要真的檢查返回值recv

有一種做,但它沒有做任何事。即使recv失敗,您仍然無法正確處理錯誤,但您永遠不會知道。

此外,您不發送終止\0這不是必要的壞,取決於你想要做什麼,例如你可以在接收後添加。

+0

我試着添加\ 0但它沒有做任何事情。我仍然會在字符串的末尾插入隨機字符。所以問題是,是什麼導致了插入?感謝recv筆記,我一直認爲每次recv都會向緩衝區中添加另一個字節,它的返回值會增加1. – Christian

+0

以及我談到錯誤處理,您如何檢查它? –

+0

好的,我認爲它是固定的。我會給你信用的^^。 – Christian

3

對不起,但

int local; 
(...) 
return (int*)local; 

什麼你想達到什麼目的?你的代碼有很多嚴重的問題。

+0

警告/錯誤食人者,因爲RecvBytes是int *並且Recv返回int。 – Christian

+1

我不明白。你從整數指向無用的指針。我的警告是否意味着分割?好吧,更清晰的想法是拋出異常。 – Nyton

2

這不是通過網絡發送數據的方式。錯誤太多了。

,如果你想通過網絡發送null結尾的字符串:

int local = send(ConnectSocket, lData, (int)strlen(lData), 0); 

爲大家說,你實際上並沒有發送空終止。如果您將長度加1,則會發送它。而且,對於長字符串,send()函數並不保證您一次發送整個字符串。你必須檢查並重新發送缺失的部分。

recv(ConnectSocket, recvbuf , recvbuflen, 0); 

你不檢查返回值,所以你可以不知道接收到的字符串的長度。由於您不發送空字節,所以收到的數據不是空終止的。另外,如果空終止符是您發送的更多數據的唯一分隔符,則必須逐字節讀取(不是有效的),不要錯過空終止符以知道何時完成。另一種方法是製作自己的緩衝方案(因此下一次讀取會部分返回前一個結果),或者更改協議以預先知道已傳輸數據的長度。此外,關於部分讀取的相同評論與send函數一樣適用於此處。

順便說一句,返回一個靜態/全局緩衝區不是好代碼的標誌。

+0

好吧,嗯,首先,我認爲它會返回? Recv將傳入的數據複製到一個緩衝區,所以當它完成時,我返回緩衝區。查看,我知道發送數據1次是容易出錯的,我必須將它們發送兩次並在客戶端比較結果。我也嘗試過,但並不能保證我想要的結果,即數據包是按原樣來來去去的。順便說一句,這是微軟的代碼,我只是將所有內容都包裝在一個類中:)。 – Christian

+0

實際上將長度增加1並通過NUL終結符發送了訣竅!感謝Steve-o先注意!和其他人的提示! – Christian

+1

@Christian您已將您的代碼從「碰巧不工作」更改爲「碰巧工作」。它仍然被大量破壞,因爲它忽略了'recv'的返回值,並將其視爲不保證爲C風格字符串的C風格字符串數據。 –