3

Winsock、C++ を使用して、send()/recv()、TCP 接続でデータを送受信します。データが相手に届いたことを確認したいのですが、 recvでデータを受信した後 (if) に確認メッセージを返信することをお勧めします。

ここに 2 つの可能性があります。どちらに進むべきかアドバイスをお願いします。

  1. sendが渡されたバッファのサイズを返す場合、データは少なくともワイヤの反対側のrecv関数に配信されていると想定します。「少なくとも」と言うとき、recvがそこで失敗したとしても(たとえば、バッファ不足などのために)、気にしないで、サーバーの一部の作業を適切に完了したことを確認したいだけです-データを完全に送信しました (つまり、データが他のマシンに到達しました)。

  2. 追加の確認応答を使用します。recvでデータを受信した後、受信したパケットの ID (送信された各データのヘッダーの一部) を送り返し、そのパケットの受信操作が成功したことを通知します。一定の間隔を置いてもそのような「確認メッセージ」を受信しない場合は、送信者関数から失敗コードを返します。

2 番目の回答の方が安全に見えますが、転送プロトコルが冗長である場合に複雑にしたくありません。また、TCP 接続について話していることにも注意してください (UDP よりも安全です)。

データが反対側のrecv関数に配信されたことを保証する他のメカニズム(おそらく他のAPI?おそらくWSARecv()/WSASend()の動作?)はありますか?

2 番目の方法をお勧めする場合は、recvをタイムアウト付きで使用して確認応答を受信できるようにするコード スニペットを教えてください。recvはブロッキング操作であるため、前回の送信試行が失敗した場合 (相手に通知されなかった場合) は永久にハングします。タイムアウトを指定してrecvを使用する簡単な方法はありますか(毎回個別のスレッドを作成することなく、おそらくすべての送信操作でやり過ぎになるでしょう)。

また、関数を送信するために渡すデータの量は非常に大きい (数メガバイト) 可能性があるため、「確認メッセージ」のタイムアウトを選択するにはどうすればよいですか? 大きなバッファを「分割」して、いくつかの送信呼び出しを使用する必要がありますか? かなり複雑になると思いますので、アドバイスお願いします!

編集: わかりました、あなたは TCP/IP スタックがそれを処理することを示唆しています(つまり、手動の承認は必要ありません)、これは私が MSDN ページで見つけたものです:この関数は、データが正常に送信されたことを示すだけです。」したがって、TCP メカニズムにデータ配信を保証する機能があるとしても、 send()関数やその他の Winsock 関数を介してそのステータス (成功かどうか) を取得することはできません。TCP層からステータスを取得する方法を知っていますか? 繰り返しますが、send()関数の戻り値が十分ではないようです!

================================================== ======

編集 2: OK、TCP プロトコルは何か問題が発生した場合のエラー処理を考慮しますが、Winsock のsend()関数はエラーを報告できないことに同意すると思います(単純に、実際のデータ送信が開始される前に返されるためです)。ネットワークドライバー)。ここで百万ドルの質問があります: Winsock のsend()関数は、少なくとも、現在のパケットが配信されるまで、他のパケットが相手に配信されないことを保証しますか? 言い換えれば、何らかのネットワーク障害で送信が失敗した場合 (しかし、send()呼び出しによって報告されない)、次のデータのチャンクでsend()関数の次の呼び出しの前にネットワーク障害が修正されます。前のパケット (失敗しましたが、によって報告されていません)send() ) は次のパケットの前に配信されますか? つまり、1 つの特定の send() 関数が「黙って」失敗し、後続の send() 呼び出しが成功しても最初のパケットが失われる可能性はありますか? 繰り返しますが、私は TCP レベルで話しているのではなく、Winsock API レベルで話しているのです!

4

4 に答える 4

3

配信を保証するために TCP/IP スタックを信頼してみてはいかがでしょうか。結局のところ、それが UDP の代わりに TCP を使用することの要点です。

于 2011-06-11T22:45:42.680 に答える
3

ここでの既存の回答はほとんど正しいです。TCP を使用する場合、ピアへのパケットの信頼性の高い配信について心配する必要はありません。

しかし、これは、データの整合性を次のレベルに引き上げる必要がある一部のシステムにとって危険な見方です。共通基準の監査要件では、監査ログで監査エントリが失われる可能性がある場合、監査可能なイベントFAU_STG.4.1を防止する機能が必要です。(たとえば、Linux監査ログ デーモンは、コンピューターをシングル ユーザー モードにするか、監査ログ用のスペースがなくなったときにシステムを完全に停止するように構成できます。)集中型ログ サーバーに正常に書き込まれたことがわかっています。auditd(8)

金融取引はおそらく、単純な TCP よりも信頼性の高いプロトコルで処理するのが最適です。資金の利用可能性を確保し、取引を実行し、取引の結果を報告するために、口座の入金または引き落としは多段階プロトコルで処理するのが最適です。原点へ。

TCP は、2 つのピア間で (極端な条件下で)ほぼギガバイトの転送中データを許可します。アプリケーションの要件によっては、データが適切に処理されたという肯定的な確認をピアから受け取るまで、送信側でそのデータを維持する必要がある場合があります。

ありがたいことに、ほとんどのアプリケーションはそれほど重要ではありません。「将来」のある時点で閉じられた接続を報告するソケットのあちこちでメガバイトのデータを失うことは、実際には恐ろしいことではありません.HTTPリクエストを再試行するか、SFTP接続を再試行するだけです.

アップデート

ソケットは、使用可能なウィンドウを埋めるのに十分なデータのみを受け入れます。ウィンドウ サイズは、セッション ハンドシェイク中に 2 つのピア間でネゴシエートされます。したがってsend()、ソケットのウィンドウがいっぱいになると、への呼び出しがブロックされ始めます。(OS、内部バッファーにもデータを追加できるようにし続ける場合がありますが、ある時点で書き込みがブロックされます。) ピアがRSTまたはICMPUnreachable メッセージで接続を切断した場合、今後のへの呼び出しsend()は Connection Reset または のエラー値を返します。壊れたパイプ。

更新 2

TCP レベルで話しているのではなく、Winsock API レベルで話している

これが混乱の元かもしれません。send()TCP で使用する場合、TCP の動作に固執するしかありません。

TCP は、パケットを配信できる範囲で、バイト ストリームの順序どおりの信頼性の高い配信を保証します。(ポニーと不注意な人々が電源コードを蹴っているという @Hans のコメントを参照してください。) ピア プログラム、送信された正しい順序でバイトを確認します。(わかりました、TCP帯域外の緊急パケット配信もありますが、実際にそれを使用するアプリケーションを見たことがありません。OOB パケットを使用すると、一部のデータをオフラインで取得できます。言及したことを忘れてください。 )

リモート プログラムが TCP ストリームで送信されたバイトを受信した場合、先行するすべてのバイトも確実に受信しました。(まあ、リモート ピアの正当なパケットと偽のパケットを接合するリプレイ攻撃にはさまざまな種類がありますが、それらは初期シーケンス番号がランダム化されたシステムではますます困難になっています。これが脅威モデルの範囲内である場合は、TLSを使用する必要があります。暗号的に強力な改ざん防止情報を提供するために TCP を使用します. しかし、TLS はより良いパケットごとの配信通知を提供することはできません.)

于 2011-06-11T23:26:42.857 に答える