24

send()基礎となるプロトコルについて議論することに関する多くの質問を見てきました。TCP の場合、メッセージが送信されるときにメッセージが分割される可能性があり、受信者が 1 つのアトミック操作でメッセージを取得するという保証がないことを十分に認識しています。この質問では、send()システム コールがローカル システムのネットワーク層と対話する際の動作についてのみ話しています。

POSIX 標準とsend()私が読んだドキュメントによると、送信されるメッセージの長さはlength引数で指定されます。長さ lengthの1 つのメッセージをsend()送信することに注意してください。さらに遠く:

送信するメッセージを保持するためのスペースが送信側ソケットで利用できず、ソケット ファイル記述子が O_NONBLOCK設定されていない場合、send()スペースが利用可能になるまでブロックします。送信するメッセージを保持するためのスペースが送信側ソケットになく、ソケット ファイル記述子がO_NONBLOCK設定されている場合、 send()失敗します。

-1この定義では、 send() が (送信されるデータがカーネルでキューに入れられていないことを意味します) またはlength以外の値を返す可能性はありません。これは、メッセージ全体がカーネルでキューに入れられていることを意味します。送信されます。つまり、カーネルで配信するメッセージをローカルでキューに入れることに関しては、send()アトミックでなければならないように思えます。

  1. メッセージ全体に対してカーネルのソケット キューに十分なスペースがあり、シグナルが発生しない場合 (通常の場合)、メッセージはコピーされ、lengthが返されます。
  2. の間に信号が発生した場合、send()それは を返さなければなりません-1。この場合、メッセージの一部をキューに入れることはできません。送信された量がわからないからです。したがって、この状況では何も送信できません。
  3. メッセージ全体に対してカーネルのソケット キューに十分なスペースがなく、ソケットがブロックされている場合、上記のステートメントに従って、send()スペースが利用可能になるまでブロックする必要があります。メッセージはキューに入れられ、lengthsend()を返します。
  4. カーネルのソケット キューにメッセージ全体に対して十分なスペースがなく、ソケットが非ブロックの場合は、send()失敗し ( が返され-1)、またはerrnoに設定されます。繰り返しますが、この状況では、メッセージのどの部分もキューに入れることができないことは明らかです。EAGAINEWOULDBLOCK-1

何か不足していますか?send() が値を返すことは可能>=0 && <lengthですか? どんな状況で?非 POSIX/UNIX システムについてはどうですか? Windows のsend()実装はこれに準拠していますか?


概念的nullには、変数が無効なオブジェクトを指していることを意味する特別な値であるため、その内容 (変数またはメソッド) にアクセスできないという意味で有効なものを参照していません。

何も参照しないポインターを持つことができると便利だったので、言語に追加された一種の特別な条件として見ることができます。しかし、ここにはいくつかの不一致があります。実際、一部の言語では、null(意味のある) 値を初期化することを強制することで、値の必要性を妨げています。

あなたの例には違いがあり、有効なオブジェクトです。有効なオブジェクトではありませんが""、空の文字列nullです。

4

6 に答える 6

12

あなたのポイント2は単純化されすぎています。sendゼロより大きいが長さ未満の値を返す通常の状態(他の人が言っているように、長さの引数がゼロの場合を除いてゼロを返すことはできないことに注意してください) は、メッセージがブロッキングを引き起こすのに十分な長さである場合です。一部のコンテンツがすでに送信された後に割り込み信号が到着します。この場合、send失敗することはありませんEINTR(これにより、アプリケーションはすでにデータを正常に送信したことを認識できなくなるため)、再ブロックできません (信号が中断されており、その全体のポイントはブロックから抜け出すことであるため)。 、したがって、すでに送信されたバイト数を返す必要があります。これは、要求された合計長よりも小さいです。

于 2013-10-31T05:09:56.273 に答える
6
  1. Posix 仕様と、私が 30 年間に見たすべてのman 2 sendsend()ページによると、はい、 > 0 および <= の任意の値を返すことができますlength。ゼロを返すことはできないことに注意してください。

  2. 数年前のニュース:comp.protocols.tcp-ip に関する議論によると、すべての TCP 実装者は、send()すべてのデータをソケット送信バッファーに転送するまで、ブロッキングは実際には返されません。つまり、戻り値は -1 または のいずれかです。これはすべての既知の実装にlength.当てはまります。write(), writev()sendmsg()writev()

于 2013-10-31T02:21:21.460 に答える
3

GNU C ライブラリを使用して、Linux でどのように機能するかを知っています。この場合、質問のポイント4の読み方が異なります。O_NONBLOCKファイル記述子のフラグを設定し、カーネル内のメッセージ全体をアトミックにキューに入れることができない場合send()、実際に送信されたバイト数 (1 から長さまでの範囲) を返し、 にerrno設定されEWOULDBLOCKます。

(ファイル記述子がブロッキング モードで動作すると、send()ブロックされます。)

于 2014-04-02T03:03:40.920 に答える
2

send()を返すことが可能ですvalue >= 0 && < length。これは、 への呼び出し時に、送信バッファにメッセージの長さよりも余裕がない場合に発生する可能性がありますsend()。同様に、送信者に知られている現在の受信者ウィンドウ サイズがメッセージの長さよりも小さい場合、メッセージの一部のみが送信される可能性があります。逸話として、受信プロセスが受信バッファから受信していたデータをアンロードするのが遅いときに、localhost 接続を介して Linux でこれが発生するのを見てきました。

私の感覚では、実際の経験は実装によってかなり異なります。この Microsoft linkから、長さ未満のエラー以外の戻り値が発生する可能性があることは明らかです。

長さ 0 のメッセージが送信された場合、戻り値 0 を取得することもできます (少なくとも一部の実装では)。

この回答は私の経験に基づいており、特にこのSOの回答を参考にしています。

編集:この回答とそのコメントから、EINTRデータが送信される前に中断が発生した場合にのみ失敗する可能性があることは明らかです。これは、そのような戻り値を取得する別の方法です。

于 2013-10-31T02:47:44.707 に答える
0

それが言うところを少し明確にするために:

スペースが空くまでブロックします。

そのブロック/スリープからウェイクアップするには、いくつかの方法があります。

  • 十分なスペースが利用可能になります。
  • シグナルにより、現在のブロック操作が中断されます。
  • SO_SNDTIMEOソケットに設定され、タイムアウトになります。
  • その他。たとえば、ソケットが別のスレッドで閉じられています。

したがって、物事は次のようになります。

  1. メッセージ全体に対してカーネルのソケット キューに十分なスペースがあり、シグナルが発生しない場合 (通常の場合)、メッセージはコピーされ、長さが返されます。
  2. send() 中にシグナルが発生した場合は、-1 を返さなければなりません。この場合、メッセージの一部をキューに入れることはできません。送信された量がわからないからです。したがって、この状況では何も送信できません。
  3. メッセージ全体に対してカーネルのソケット キューに十分なスペースがなく、ソケットがブロックされている場合、上記のステートメントに従って、send() はスペースが利用可能になるまでブロックする必要があります。その後、メッセージはキューに入れられ、send() は長さを返します。 その後send()、シグナルによって中断される可能性があり、送信タイムアウトが経過する可能性があります...短い送信/部分書き込みを引き起こします。合理的な実装ではerrno、送信バッファに何もコピーされていない場合、-1 が返され、適切な値が設定されます。
  4. カーネルのソケット キューにメッセージ全体に対して十分なスペースがなく、ソケットが非ブロッキングの場合、send() は失敗し (-1 を返す)、errno が EAGAIN または EWOULDBLOCK に設定されます。繰り返しますが、-1 を返すので、この状況ではメッセージのどの部分もキューに入れることができないことは明らかです。
于 2014-02-24T13:22:44.427 に答える