2009-05-21 16 views
1

私は2つの簡単なプログラムは、UNIXドメインソケットを介して共有データをセットアップしている必要があります。 1つのプログラムがキューからデータを読み取り、それを他のアプリケーションに送信します。それが送信される前に、各データは長さが4バイトで前に付加されます.4バイト未満であれば、左上のバイトは '^'シンボルです。unixドメインストリームソケットより多くのデータを送信する必要がありますそれは

クライアントアプリケーションは、最初の4バイトを読み取り、バッファを適切なサイズに設定して残りを読み取ります。私が抱えている問題は、最初のメッセージを通して完璧に送られるということです。それ以降は、余分なデータが送られてくるので、「いい日が出てきた」のようなメッセージが出てくるでしょう。だから私はバッファが正しくクリアされていないように感じるが、私はそれを見つけるように見えない。

クライアントコード:

listen(sock, 5); 
for (;;) 
{ 
    msgsock = accept(sock, 0, 0); 
    if (msgsock == -1) 
     perror("accept"); 
    else do 
    { 
     char buf[4]; 
     bzero(buf, sizeof(buf)); 
     if ((rval = read(msgsock, buf, 4)) < 0) 
     perror("reading stream message"); 

     printf("--!%s\n", buf); 

     string temp = buf; 
     int pos = temp.find("^"); 
     if(pos != string::npos) 
     { 
      temp = temp.substr(0, pos); 
     } 

     int sizeOfString = atoi(temp.c_str()); 
     cout << "TEMP STRING: " << temp << endl; 
     cout << "LENGTH " << sizeOfString << endl; 
     char feedWord[sizeOfString]; 
     bzero(feedWord, sizeof(feedWord)); 

     if ((rval = read(msgsock, feedWord, sizeOfString)) < 0) 
       perror("reading stream message"); 

      else if (rval == 0) 
       printf("Ending connection\n"); 
      else 
       printf("-->%s\n", feedWord); 
       bzero(feedWord, sizeof(feedWord)); 
       sizeOfString = 0; 
       temp.clear(); 
     } 
     while (rval > 0); 
     close(msgsock); 
    } 
    close(sock); 
    unlink(NAME); 

サーバコード

   pthread_mutex_lock(&mylock); 
       string s; 
       s.clear(); 
       s = dataQueue.front(); 
       dataQueue.pop(); 
       pthread_mutex_unlock(&mylock); 

       int sizeOfString = strlen(s.c_str()); 
       char sizeofStringBuffer[10]; 

       sprintf(sizeofStringBuffer, "%i", sizeOfString); 
       string actualString = sizeofStringBuffer; 
       int tempSize = strlen(sizeofStringBuffer); 

       int remainder = 4 - tempSize; 
       int x; 
       for(x =0; x < remainder; x++) 
       { 
        actualString = actualString + "^"; 
       } 

       cout << "LENGTH OF ACTUAL STRING: " << sizeOfString << endl; 

       actualString = actualString + s; 

       cout << "************************" << actualString << endl; 
       int length = strlen(actualString.c_str()); 

       char finalString[length]; 
       bzero(finalString, sizeof(finalString)); 
       strcpy(finalString, actualString.c_str()); 

          if (write(sock, finalString, length) < 0) 
          perror("writing on stream socket");  

答えて

2

むしろ '^' であなたのパケット長をパディングよりも、あなただけやってオフにはるかに良いだろう:

snprintf(sizeofStringBuffer, 5, "%04d", sizeOfString); 

の値が0になるようにしてください。 - 受信者の '^'文字を解析する必要はありませんコード。

また、デバッグコードを編集してください - 現在のコードにはwrite()が1つしかなく、プロトコルの説明と一致しません。

理想的には、送信ルーチンを独自の関数に分割します。また、writev()を利用して、「長さ」フィールドを保持する文字列と実際のデータを保持するバッファーとの融合を処理し、それらを単一のアトミックwrite()として送信することができます。

未テストコードは次のとおりです。

int write_message(int s, std::string msg) 
{ 
    struct iovec iov[2]; 
    char hdr[5]; 

    char *cmsg = msg.c_str(); 
    int len = msg.length(); 

    snprintf(hdr, 5, "%04d", len); // nb: assumes len <= 9999; 

    iov[0].iov_base = hdr; 
    iov[0].iov_len = 4; 

    iov[1].iov_base = cmsg; 
    iov[1].iov_len = len; 

    return writev(s, iov, 2); 
} 
+0

これは私にとっては良い解決策のように見えますが、私はreadvと何をするのか少し混乱しています。読み込み側では、バッファをiov [0]のサイズに設定するだけです。iov_lenを作成し、そのバッファにiov [1] .iov_baseを指定します。この場合は – whatWhat

+0

ですが、readvを使用することはできません。最初に4バイトの長さのフィールドを読み取ってから、指定された長さの2番目のバッファを読み取る必要があります。 – Alnitak

+0

まだ問題のコードの根本的な問題を解決していません。つまり、読み込まれる文字列がヌルで終了していないため、printf()はその文字列を出力します。遭遇した。 – Beano

2

あなたは-1のためではなく、短いのためだけでなく、writeread両方の戻り値をチェックする必要があり(以下、要求された)/読み込み書き込みます。また、perrorでエラーを印刷した後に続行すると思われます。exit(2)などを実行してください。

0

2つのこと:

ファースト - サーバ側で、あなたの配列の末尾をオフに書いています。

char finalString[length]; 
bzero(finalString, sizeof(finalString)); 
strcpy(finalString, actualString.c_str()); 

strcpy()は(ヌルターミネータを引く文字)finalStringlength+1文字をコピーします。

クライアント側では、あなたが読み込んだ文字列を終了していないので、printf()はあなたの文字列を印刷し、次にそれが何であれポイントまでスタックに印刷されますヌルに当たる。

両方のバッファを1つ増やすと、より良い形になります。

関連する問題