2009-04-09 11 views
3

これは、ソケット上のreadを反復処理する適切な方法ですか?私はこれを正しく動作させるのに苦労しています。 data.sizeunsigned intで、ソケットからも入力されます。合ってます。 data.dataunsigned char *です。ソケットからread()を反復する

if (data.size > 0) { 
    data.data = (unsigned char*)malloc(data.size); 
    memset(&data.data, 0, data.size); 
    int remainingSize = data.size; 
    unsigned char *iter = data.data; 
    int count = 0; 
    do { 
     count = read(connect_fd, iter, remainingSize); 
     iter += count; 
     remainingSize -= count; 
    } while (count > 0 && remainingSize > 0); 
} 
else { 
    data.data = 0; 
} 

ありがとうございます。

答えて

9

戻り値を他の値に追加する前に、読み込み値をチェックする必要があります。

ソケットがEOFを報告するとゼロになり、エラーの場合は-1が返されます。ソケットのEOFは閉じたものと同じではないことに注意してください。

3

低レベルソケットプログラミングは非常に面倒でエラーが発生しやすいです。 C++を使用している場合は、BoostACEのような上位ライブラリを使用するようにしてください。

私はまた、while条件の一部として読み取りを入れC++ Network Programming: Mastering Complexity Using ACE and PatternsC++ Network Programming: Systematic Reuse with ACE and Frameworks

+0

特にブーストアシオ。 –

+0

oops :-)これは、人が入力してコピー&ペーストしないときに起こります;-) – lothar

3

を読むことをお勧めします。

while((remainingSize > 0) && (count = read(connect_fd, iter, remainingSize)) > 0) 
{ 
    iter += count; 
    remainingSize -= count; 
} 

このようにして失敗した場合、すぐにループを停止します。
ループ条件の一部として読み込みを使用するのは非常に一般的なパターンです。そうでない場合は、コードを醜くするループ内の状態をチェックする必要があります。

個人的には:
私は上記のテスト全体を別の機能に分けて読みやすくしていますが、あなたの気分は非常に良いかもしれません。

また、malloc(および会社)を使用すると、メモリ管理に関する問題が発生する可能性があります。私はstd :: vectorを使います。これにより、例外を投げ始めるためにコードを修正するときに、コードが将来証明されますが、今度は例外安全です。

だから、あなたは、このようにSTDの種類::ベクトル、その後

if (data.size > 0) 
{ 
    std::vector<unsigned char> buffer(data.size); 

    unsigned char *iter = &buffer[0]; 
    while(... read(connect_fd, iter, remainingSize)) 
    { 
     ..... 
    } 

    ... handle error as required 

    buffer.resize(buffer.size() - remainingSize); 
    data.data.swap(buffer); 
} 
3

< unsigned char型>システムコールです()の呼び出し読んで覚えておいてください、可能なブロックのソースを持っているdata.dataを変更すると仮定すると、および非ブロッキングI/Oを使用していても、本質的に重量があります。私はそれらを最小化することをお勧めします。

良い方法は、C言語でBSDソケットプログラミングの10年以上にわたり、常に非ブロッキングI/Oを使用してFIONREAD ioctl()を発行して、待機中のデータの総量を取得することです。 (あなたがselect()のような何らかの同期I/Oマルチプレクサを使っていると仮定して)与えられたポーリング間隔と、それをすべてキャプチャするのに必要な回数だけread()を読んでから、次のタイマーティックまで。

関連する問題