5

多くの人は、元の「send()」が要求したバイト数をワイヤに書き込めないことを知っています。簡単にポインターとループを使用して、データがすべて送信されていることを確認できます。

ただし、この場合、WSASend() と完了ポートがどのように機能するかわかりません。すぐに返され、送信された量を制御することはできません (ルーチンでアクセスできる lpLength を除く)。これはどのように解決されますか?

すべてのデータを取得するために、ルーチンで WSASend() を複数回呼び出す必要がありますか? これは、特にデータを特定の順序で出力する必要があり、複数のスレッドがルーチンにアクセスする場合、大きな欠点のように思えませんか?

4

3 に答える 3

9

および構造体WSASendに関連付けられているソケットを使用して呼び出すと、データをネットワーク スタックに効果的に渡して送信できます。使用したデータ バッファーがネットワーク スタックで不要になると、ネットワーク スタックは "完了" を返します。その時点で、データ バッファーに使用されているメモリを自由に再利用または解放できます。IOCPOVERLAPPED

完了が生成された時点でデータがピアに到達している可能性は低く、完了の生成は、ネットワーク スタックがバッファの内容の所有権を取得したことを意味するだけであることに注意してください。

これはsend操作方法が異なります。sendブロッキング モードでは、指定したすべてのデータがネットワーク スタックで使用されるまで、 への呼び出しがsendブロックされます。ノンブロッキング モードでの呼び出しの場合send、ネットワーク スタックはバッファからできるだけ多くのデータを取得し、使用量の詳細を返します。これは、データの一部が使用されたことを意味します。ではWSASend、通常、通知される前にすべてのデータが使用されます。

WSASendリソースの制限やネットワーク エラーが原因で、オーバーラップが失敗する可能性があります。すべてではなく一部のデータが送信されたことを示すエラーが発生することはまれです。通常、すべて正常に送信されるか、まったく送信されません。ただし、すべてではなく一部のデータが使用されたことを示すエラーで完了を取得することは可能です。この時点からどのように進めるかは、エラー (一時的なリソース制限またはハード ネットワーク障害) とWSASend、そのソケットで保留中の の数 (ゼロまたはゼロ以外) によって異なります。一時的なリソース エラーがあり、他に未解決のエラーがない場合にのみ、残りのデータを送信してみてください。WSASendこのソケットを呼び出します。これは、一時的なリソース制限の状況がいつ通過するかわからないという事実によって、より複雑になります...一時的なリソース制限によって部分的な送信が引き起こさWSASendれ、保留中の他の呼び出しがある場合は、おそらく中断する必要がありますこのWSASend呼び出しからバッファの一部を送信してから、後続の呼び出しのすべて (または一部) を送信することにより、データ ストリームを文字化けした可能性があるためですWSASend

WSASendソケットで複数の呼び出しを未処理にすることは、a) 有用であり、b) 効率的であることに注意してください。これが、接続を最大限に活用する唯一の方法です。WSASendただし、一度に複数のオーバーラップした呼び出しを保留することによるメモリとリソースの使用量の影響に注意する必要があります(ここを参照)。これは、バッファの有効期間 (したがって、メモリとリソースの量) の制御を効果的に処理しているためです。 TCP フロー制御の問題により、コードはピアに) を使用します)。ほらSIO_IDEAL_SEND_BACKLOG_QUERYSIO_IDEAL_SEND_BACKLOG_CHANGE本当に賢くなりたいなら...

于 2013-01-16T09:18:31.840 に答える
3

WSASend()要求されたすべてのデータがソケットによって受け入れられるまで、またはエラーが発生するまで、完了ポートでは通知されません。すべてのデータが受け入れられる (またはエラーになる) まで、バックグラウンドで動作し続けます。通知されるまで、そのバッファーはメモリ内でアクティブなままにしておく必要がありますが、WSASend()ビジー状態の間、コードは自由に移動して他のことを行うことができます。データが実際にピアに送信されるときに通知はありません。それが必要な場合は、データを受信したときにピアが通知できるように、データ プロトコルに ACK を実装する必要があります。

于 2013-01-16T01:54:12.500 に答える
0

まずについてsend。実際には、ソケットの構成方法に応じて、2 つの異なることが発生する可能性があります。

ソケットがいわゆるブロッキング モード (デフォルト) の場合、 への呼び出しは、基になるネットワーク ドライバーによってすべての入力バッファーが消費されるまで、呼び出し元のスレッドsendブロックします。(これは、データがすでにピアに到着していることを意味するわけではないことに注意してください)。

ソケットが非ブロッキング モードに転送された場合 -基になるドライバーがすべての入力をすぐに消費しない可能性がある場合、への呼び出しsend失敗します。そんな場合のGetLastError返品です。WSAEWOULDBLOCKアプリケーションは、送信を再試行できるようになるまで待機する必要があります。ループで呼び出す代わりにsend、アプリケーションはシステムからソケット状態の変更に関する通知を取得する必要があります。WSAEventSelectまたはなどの関数がWSAAsyncSelectこれに使用される場合があります (および legacy select)。

ここで、I/O 完了ポートを使用するとWSASend、話は多少異なります。ソケットが完了ポートに関連付けられている場合、自動的に非ブロッキング モードに移行します。

への呼び出しをWSASendすぐに完了できない場合 (つまり、ネットワーク ドライバーがすべての入力を消費できない場合)、WSASendはエラーをGetLastError返し、 を返しますSTATUS_PENDING。これは実際には、非同期操作が開始されたがまだ終了していないことを意味します**。

つまりWSASend、送信操作が既に進行中であるため、繰り返し呼び出すべきではありません。完了すると (成功したかどうかに関係なく)、I/O 完了ポートで通知を受け取りますが、その間、呼び出し元のスレッドは自由に他のことを行うことができます。

于 2013-01-15T22:26:09.243 に答える