2017-01-12 4 views
1

Cソケットに整数値を書き込み、読み込みしようとしています。ときどきntohs()は55000、32000などの非常に大きな値を返します。クライアントは常に<という値を送信しますが、プログラムを実行すると10〜15分後に発生します... 20〜30分後に発生することがあります。ntohs()問題:Cソケットに整数を書き込む

コードを確認して教えてください なぜこの行が印刷されますか?

printf( "Garbage value - ntohs problem .Exiting ...");

// write exactly n byte 
inline int write_n(int fd, char *buf, int n) { 

    int nwrite, left = n; 
    int totalwrite = 0; 

    while (totalwrite != n) { 
     if ((nwrite = write(fd, buf, left)) <= 0) { 
      break; 
     } else { 
      totalwrite = totalwrite + nwrite; 
      left -= nwrite; 
      buf += nwrite; 
     } 

    } 
    if (totalwrite == 0) 
     return nwrite; 
    return totalwrite; 
} 

// send exactly n byte 
inline int send_n(int fd, char *buf, int n) { 

    int nwrite, left = n; 
    int totalwrite = 0; 

    while (totalwrite != n) { 
     if ((nwrite = send(fd, buf, left, MSG_NOSIGNAL)) <= 0) { 
      break; 
     } else { 
      totalwrite = totalwrite + nwrite; 
      left -= nwrite; 
      buf += nwrite; 
     } 

    } 
    if (totalwrite == 0) 
     return nwrite; 

    return totalwrite; 
} 



uint16_t nread, len, plength, nsend; 
int MTU = 1500; 
char buffer[2000]; 

// Server receive (Linux 64 bit) 
while (1) { 
    // read packet length 
    nread = read_n(TCP_SOCKFD, (char *) &plength, sizeof(plength)); 
    if (nread <=0) { 
     break; 
    } 

    len = ntohs(plength); 
    if (len <=0 || len > 1500) { 
     **printf("Garbage value - ntohs problem ..Exiting... "); // WHY ?** 
     break; 
    } 

    // read packat data 
    nread = read_n(SOCKFD, buffer, len); 
    if (nread != len) { 
     break; 
    } 

} 

//--------------------- 
// CLIENT send (Android 5) 
while (1) { 

    nread = read(tunfd, buffer, MTU); 

    if (nread <= 0 || nread > 1500) { // always <=1500 
     break; 
    } 

    plength = htons(nread); 
    // send packet lenght 
    nsend = send_n(TCP_SOCKFD, (char *) &plength, sizeof(plength)); 
    if (nsend != sizeof(plength)) { 
     break; 
    } 
    // send packet data 
    nsend = send_n(TCP_SOCKFD, buffer, nread); 
    if (nsend != nread) { 
     break; 
    } 

} 

あなたが検証可能な例を提供することができないので、我々は何が起こっているのか確実にあなたを伝えることができないあなたに

+0

もし '/ len == 0'のときに/が表示されないのは間違いないでしょうか?また、 'len'は' uint16_t'です.0より小さくすべきではありません。確かにいくつかのコンパイラの警告があります。 – yano

+1

1) 'read_n()'の宣言/定義の投稿を検討してください。2)私は 'nread = read_n(TCP_SOCKFD、(char *)&plength、sizeof(plength))を期待しています。 if(nread chux

+1

'printf("ガベージ値%X - ntohsの問題.Exiting ... "、1u * len)'はより有益です。 – chux

答えて

2

ありがとうございます。さらに、read_n()の実装は提示していませんが、write_n()send_n()と同じモデルに従うと仮定しても、何らかの分析を行うことができます。

各データ転送関数は、データ転送がエラーによって中断された場合に短いカウントを返します。クライアントコードはこれを監視し、ループを検出するとループから抜け出します。まあ、良い。ただし、サーバコードplengthを読むときにを実行しません。 plengthから、uint16_tとして2バイトのサイズですが、部分的な読み取りが可能であり、サーバーコードによって気付かれません。

この例では、plengthは、read_n()コールでのみ変更されます。ネットワークバイトオーダーはビッグエンディアンなので、最上位バイトが最初に読み込まれます。例えば、221(0x00dd)バイトのパケットの後ろに1280(0x0500)バイトのパケットが続く場合、そのバイトの組み合わせは、第2のパケットサイズで部分読み取りが行われた場合、結合された結果は1501(0x05dd)になります。

現在のところ、クライアントがあなたとは異なる性質のデータを送信していると思われる理由はありません。私は現在、サーバーコードが異なるデータを受け取るように見える特に、クライアントとサーバが最初に認識された障害の兆候で中止するため、クライアントが送信するよりも優先されます。

ただし、このコードをより堅牢にすることができます。特に、基礎となるソケットまたはデータ転送要求に問題がない場合でも、read(),write()、およびsend()が失敗する可能性があることを考慮してください。特に、シグナルによって割り込みが発生した場合はEINTRで失敗し、ソケットが非ブロックモードの場合はEAGAINで失敗する可能性があります。他にもあるかもしれない。ノンブロッキングモードでソケットを操作するのは便利ではないようですが、実際にEINTRを見て、受信後に読書を再開したいと思うかもしれません。

少なくとも、開発中は、エラーの性質についてより多くのデータを出力することをお勧めします。たとえば、perror()を呼び出して、その後に不良データを印刷します。ロギングされたデータを送受信することも考えられます。

+0

ありがとうございます。あなたが提案したように、接続が予期せず終了したときに部分データが読み込まれていることがわかりました。したがって、ntohsによってガベージ値が返されます。そこで、接続の終了を検討することができます。ありがとう – NetTech

関連する問題