17

TCP ソケットで読み取り可能なバイト数を知りたいと思っています。私はフラグ「FIONREAD」を指定して ioctl を呼び出しています。これにより、実際にこの値が得られるはずです。関数を呼び出すと、 return val 0 (したがって Error はありません) として取得されますが、整数引数も値 0 を取得します。それは問題ありませんが、recv() メソッドを呼び出すと、実際にソケットからいくつかのバイトを読み取ります。私は何を間違っていますか?

// ここにいくつかのコード:

char recBuffer[BUFFERLENGTH] = {0};
int bytesAv = 0;
int bytesRead = 0;
int flags = 0;
if ( ioctl (m_Socket,FIONREAD,&bytesAv) < 0 )
{
    // Error
}
if ( bytesAv < 1 )
{
    // No Data Available
}
bytesRead = recv(m_Socket,recBuffer,BUFFERLENGTH,flags);

recv 関数を呼び出すと、実際にいくつかの有効なデータを読み取りました (これは期待していました)。

4

4 に答える 4

15

それは非常に急速に起こっているので、何も見えません。あなたがしていること:

  • ioctl: データはありますか? いいえ、まだ何もありません
  • recv: データがあるまでブロックします。少し(短い)後:これがあなたのデータです

ですから、本当に見たい場合はFIONREAD、それを待ってください。

/* Try FIONREAD until we get *something* or ioctl fails. */
while (!bytesAv && ioctl (m_Socket,FIONREAD,&bytesAv) >= 0)
    sleep(1);
于 2011-08-08T09:18:11.347 に答える
13

ここでの本当の答えは、 cnicutar が言ったように select(2) を使用することです。トビー、あなたが理解していないのは、競合状態にあるということです。まず、ソケットを見て、そこに何バイトあるか尋ねます。次に、コードが「ここにデータがありません」ブロックを処理している間、アプリケーションとは非同期のハードウェアと OS によってバイトが受信されます。そのため、recv() 関数が呼び出されるまでに、「利用可能なバイトがありません」という答えはもはや真実ではありません...

if ( ioctl (m_Socket,FIONREAD,&bytesAv) < 0 )
{ // Error 
}

// BYTES MIGHT BE RECEIVED BY HARDWARE/OS HERE!

if ( bytesAv < 1 ) // AND HERE!
{
    // No Data Available
    // BUT BYTES MIGHT BE RECEIVED BY HARDWARE/OS HERE!
}

// AND MORE BYTES MIGHT BE RECEIVED BY HARDWARE/OS HERE!

bytesRead = recv(m_Socket,recBuffer,BUFFERLENGTH,flags);
// AND NOW bytesRead IS NOT EQUAL TO 0!

確かに、わずかな睡眠で 2 年前にプログラムが修正された可能性があります。

さらに、Karoly Horvath が言ったように、ユーザーが渡したバッファに格納できる以上のバイトを読み取らないように recv に指示できます。その後、関数インターフェイスは「この fn はソケットで利用可能なバイト数を返しますが、 [渡したバッファ サイズ] 以下です。」

これは、この関数がバッファのクリアについて心配する必要がないことを意味します。呼び出し元は、関数からすべてのバイトをクリアするために必要な回数だけ関数を呼び出すことができます (または、データ ホールセールを破棄し、特定のデータ収集関数でその機能を結び付けない別の fn を提供することもできます)。あまりにも多くのことをしないことで、関数はより柔軟になります。次に、特定のアプリケーションのデータ転送のニーズに適したラッパー関数を作成できます。その fn は、その特定のアプリの必要に応じて get_data fn と clear_socket fn を呼び出します。今、あなたはプロジェクトからプロジェクトへと持ち運ぶことができるライブラリを構築しています。コードを持ち歩ける雇用主がいるほど幸運であれば、仕事から仕事へと持ち運ぶことができるかもしれません。

于 2013-08-14T02:02:09.680 に答える
5

select() を使用し、次に ioctl(FIONREAD) を使用し、次に recv() を使用します。

于 2013-02-09T15:39:28.673 に答える
4

ブロッキング I/O recv() を使用している場合、データが利用可能になるまでブロックされます。

于 2011-08-08T09:09:05.533 に答える