2011-09-10 104 views
2

私はWinsock2ラッパークラス(クライアント/サーバー)に問題があります。何度も何度も悩んでいます。あなたの意見。C++、Send()関数が余分なバイトを送信する

具体的には、問題は、Send()関数を使用するたびに、クライアントとサーバーの両方が(必ずしも!)1つまたは2つの余分なバイトを送信することです。

たとえば、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

とても早く答えることに感謝します! Heresは、私は文字列の最後に '\ 0'を追加しましたが、何もしませんでした。私はまだランダムな挿入を取得します。 – Christian

+1

@christian:すでに文字列リテラルを介して暗黙的に\ 0があります。それを送信するためには、send()コールでsizeパラメータを調整する必要があります。 strlen(lData)からstrlen(lData)+1に変更して末尾の\ 0を含めます。なぜこれが必要なのかまだわからない場合は、[strlen()](http://cplusplus.com/reference/clibrary/cstring/strlen/)関数を調べてください。 – ComicSansMS

答えて

1

実際にはrecvの戻り値を確認してください。

do-whileがありますが、何もしません。 recvが失敗しても適切なエラー処理を行わずに関数から戻りますが、それは決してわかりません。

また、あなたがやっていることに依存して、悪いことではない終端の\0を送信しないでください。たとえば、受信後に追加することができます。

+0

\ 0を追加しようとしましたが、何もしませんでした。私はまだ文字列の最後にランダムな文字を挿入します。だから、問題は、まだ、挿入の原因は何ですか? recvノートをありがとう、私はいつもrecvがバッファに別のバイトを追加すると思っていました。戻り値は1だけ増えます。 – Christian

+0

よくエラーを処理する方法について調べました。 –

+0

さて、私はそれが修正されたと思う。私はそれのためにあなたにクレジットを与えます^^。 – Christian

3

恐れ入りますが、

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

あなたが達成しようとしていましたか?あなたのコードには多くの深刻な問題があります。

+0

RecvBytesがint *で、Recvがintを返すため、警告/エラーが発生します。 – Christian

+1

私は分かりません。あなたは意味を持たない整数からポインタを作ります。私の警告はsegfaultingを意味しましたか?さて、はるかに明確なアイデアは例外をスローすることです。 – Nyton

2

これはネットワーク経由でデータを送信する方法ではありません。エラーが多すぎます。

あなたは、ネットワーク上でヌル終端文字列を送信する場合:誰もが言ったように

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

は、あなたが実際にヌルターミネータを送信しません。長さに1を加えれば、あなたはそれを送っていたでしょう。さらに、長い文字列の場合、send()関数は文字列全体を一度に送信することを保証しません。それをチェックして、不足している部分を再送信する必要があります。

recv(ConnectSocket, recvbuf , recvbuflen, 0); 

戻り値をチェックしないため、受信した文字列の長さを知ることができません。 nullバイトを送信しないので、受信したデータはNULLで終了しません。また、ヌルターミネータが送信するデータのデリミタが唯一の場合は、終了するタイミングを知らせるためにヌルターミネータを見逃さないようにバイト単位(効率的ではない)を読み取る必要があります。別の方法として、独自のバッファリングスキームを作成することもできます(次の読み取りでは前回の結果が部分的に返されます)。または、プロトコルを変更して、転送されたデータの長さを事前に知ることができます。また、ここではsend関数の場合と同じように、部分的な読み取りに関する同じ注意が適用されます。

静的/グローバルバッファを返すことは、良いコードの兆候ではありません。

+0

申し訳ありませんが、まず、私はそれが返されると思いますか? Recvは入ってくるデータをバッファにコピーするので、完了したらbuffer.Lookを返します。データを1回送信するとエラーが発生しやすく、2回送信してクライアントの結果を比較する必要があります。私もそれを試しましたが、私が望む結果を保証するものではありません。パケットはそのまま出て行きます。 BTWこれはマイクロソフトのコードです、私はクラスのすべてをラップしています:)。 – Christian

+0

実際に長さを1ずつ増やし、NULターミネータを送信することはそのトリックでした!最初に気づいたSteve-oに感謝します!そしてあなたのヒントの他のみんな! – Christian

+1

@Christianあなたはコードが「うまくいかない」から「うまくいく」に変更しました。これは 'recv'からの戻り値を無視し、Cスタイルの文字列データであることが保証されていないので、大量に壊れています。 –

関連する問題