Linuxネットワークプログラミングのさまざまな落とし穴

TCP / IPプロトコル関連

1.遅延ack

プロトコルスタックがTCPデータを受信すると、必ずしもすぐにACK応答を送信するわけではありませんが、タイムアウトを待つか、特別な条件を満たす前に送信する傾向があります。Linux実装の場合、これらの特別な条件は次のとおりです。

1)受信データがフルフレームサイズを超えている 
2)または高速応答モードで 
3)またはシーケンス外のパケットが表示される 
4)または受信ウィンドウに十分なデータがある

受信者に書き戻すデータがある場合、ACKもライドとともに送信されます。上記の条件が満たされない場合、受信機はACKに応答する前に40ms遅延します。

2.Nagleアルゴリズム

Nagleアルゴリズムの要件:

  • TCP接続には、最大で1つの未確認の未完成の小さなパケットしか含めることができず、宛先に到達する前に他のパケットを送信することはできません。
  • 最後の小さなパケットが宛先に到達する前、つまりackを受信する前に、TCPは後続の小さなパケットを収集します。最後の小さなパケットのackが受信されると、TCPは収集された小さなパケットを1つの大きなパケットにマージして送信します。

 

 

delay ackおよびnagleアルゴリズムを通じて、RTT遅延が非常に小さい場合に何が起こるかを考えます。RTTが1msの場合、「l」文字を送信してから待機(1ms + 40ms + 1ms)する必要がありますが、データ転送効率が低下します。この状況では、通常、次の解決策があります。

  • writev関数を使用して、書き込みを集約します。
  • 最初の4バイトと最後の396バイトをアプリケーション層の単一のバッファーにコピーしてから、writeを1回呼び出します。
  • TCP_NODELAYを使用して、Nagleアルゴリズムをオフにします。 

読み取り/書き込み機能

1.読み取り/書き込み機能は非ブロッキングに設定でき、デフォルトではブロッキングです。各ソケットには、カーネル内に独自の送信バッファーと受信バッファーがあります。読み取り/書き込み機能は、カーネルバッファーとの間でデータを送受信するだけです。データがいつネットワークに送信されるかについては、わかりません。

2.カーネルの受信バッファーが空であるか、送信バッファーがいっぱいである場合、読み取り/書き込み関数を呼び出すと、非ブロッキング条件、errno = EAGAINまたはEWOULDBLOCK(2つの値は等しい)ですぐに-1が返されます。

3.マシンAのプロセスaがマシンBのプロセスbと通信していると仮定します。特定の瞬間に、アプリケーションに関係なく、プロセスbが終了すると、aはソケットの読み取り呼び出しをブロックします(または非ブロックでソケットをポーリングします)。プログラムは明示的にソケットを閉じますか(OSはプロセスの最後にすべてのファイル記述子を閉じる責任があり、ソケットの場合は反対側にFINパケットを送信します)。しかし、想像したほど単純なことではありません。TCP接続を正常に閉じるには、両方の当事者のアプリケーションが合意に準拠する必要があるだけでなく、途中でエラーが発生することもありません。

  3.1 bプロセスが異常終了した場合、OSはFINパケットを送信するジョブを実行しbプロセスは存在しなくなります。マシンBがソケットからメッセージを再度受信すると、RSTで応答します(プロセスが原因であるため)ソケットを所有しているが終了しました)。RSTを受信するソケットで書き込みを処理する場合、オペレーティングシステムはSIGPIPEを送信してを処理します。デフォルトの処理アクションはプロセスを終了することです。

  3.2 プロセスbの終了とは異なり(OSは開いているすべてのソケットにFINパケットを送信する責任があります)、マシンBのOSがクラッシュしたとき(すべてのプロセスの終了アクションは引き続き実行できるため、手動シャットダウンとは異なることに注意してください)シャットダウン中に保証されます)/ホスト電源がオフの場合/ネットワークに到達できない場合、プロセスは接続終了のリマインダーとしてFINパケットをまったく受信しません

  • プロセスが読み取り時にブロックされた場合、結果は永久に待機することしかできません。
  • 最初に書き込みを処理してから読み取りをブロックした場合、TCPはマシンBのTCP / IPスタックからACKを受信できないため、12回再送信を続け(期間は約9分)、エラーを返します。ブロックされた読み取り呼び出し:ETIMEDOUT / EHOSTUNREACH / ENETUNREACH。マシンBがある時点でマシンAとのパスを再開し、再送信されたaのパックを受信すると、マシンBはそれを認識できないため、RSTを返します。このとき、プロセスaでブロックされた読み取り呼び出しはエラーECONNRESTを返します。

4.ソケットの読み取り/書き込みはいつですか?

      4.1ソケットは読み取り可能です:

  • ソケットカーネルは、バッファ内のバイト数がその最低水準点SO_RCVLOWAT以上であることを受け入れます。この時点で、ブロックせずにソケットを読み取ることができ、読み取り操作によって返されるバイト数は0より大きくなります。
  • ソケット通信パートナーは接続を閉じ、この時点でソケットの読み取り操作は0を返します。
  • リスニングソケットに新しい接続要求があります。
  • ソケットに未処理のエラーがあります。この時点で、getsockoptを使用してエラーを読み取ってクリアできます。

      4.2ソケットを書くことができます

  • ソケットコア送信バッファで使用可能なバイト数が、その最低水準点SO_SNDLOWAT以上です。この時点で、ブロックせずにソケットに書き込むことができ、書き込み操作によって返されるバイト数は0より大きくなります。
  • ソケットの書き込み操作は閉じられます。書き込み操作が閉じているソケットで書き込み操作を実行すると、SIGPIPE信号がトリガーされます。
  • ソケットが非ブロッキング接続を使用して接続に成功または失敗した後(タイムアウト)。
  • ソケットに未処理のエラーがあります。この時点で、getsockoptを使用してエラーを読み取ってクリアできます。

5、EINTR(エラー割り込み)

  読み取りおよび書き込み関数は、信号によって中断できる関数です。関数が中断されると、エラー(-1)が返され、errno変数がEINTRに設定されます。sigactionが登録されているときにSA_RESTARTオプションをオンにすることができます。関数が中断を検出すると、関数はエラーを返しませんが、自動的に再起動します。

機能を受け入れる

1.クライアントとサーバーがスリーウェイハンドシェイクを正常に確立すると、  ESTABLISHED 状態になります。サーバーが受け入れる前に、クライアントはソケットを閉じます(so_LINGERオプションをソケットに設定する必要があり、RSTメッセージは次のようになります。ソケットが閉じているときに通常のFINメッセージの代わりに送信されます)RSTメッセージを送信すると、サーバーは受け入れ機能を実行します。さまざまなオペレーティングシステムに応じて、次のことが発生します。

  •  受け入れるときは静かに接続を切断します。
  • ECONNABORTEDの返品を受け入れましょう。
  • 正常に受信されました。ただし、読み取りまたは書き込み時にECONNRESETエラーが返されます。

クローズ関数

close関数を使用してソケットを閉じると、次の動作はSO_LINGERソケットオプションに関連します。

SO_LINGERオプションを設定するときに構造が必要です

struct linger {
  l_onoff;   //开关,0为关闭SO_LINGER选项,不等于0为打开
  l_linger;  //延滞时间,单位为秒。
}

デフォルトでは、SO_LINGERオプションはオフになっています。現時点では、メンバーl_onoff = 0です。この場合、l_lingerは役に立ちません。

  1. l_onoff == 0、{off、〜}、これはシステムのデフォルト条件です。このとき、l_lingerは無視され、closeはすぐに戻ります。送信バッファにデータが残っている場合、システムはこれらのデータをバックグラウンドで反対側に送信し、最後にFINを反対側に送信します。
  2. l_onff != 0 && l_linger == 0 、{on、0}の場合、close関数はすぐに戻り、送信バッファ内の残りのデータは破棄され、RSTはすぐに反対側に送信されます。
  3. l_onff != 0 && l_linger > 0、{on、> 0}、closeは、次の2つの状況のいずれかが発生し、戻り値が0になるまでブロックします。

      a)すべてのデータ(FINを含む)が送信され、反対側のackが取得されました。この場合、事前に返されます。

       b)遅延時間がアップしています(l_lingerで指定された時間(秒単位))。

設定方法

struct linger lgr;
lgr.l_onoff = 1;
lgr.l_linger = 5;

setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &lgr, sizeof(lgr));

(受け入れる)よくある間違い

  • EAGAIN:11、リソースが一時的に利用できません理由は、システムリソースが一時的に利用できないためです。解決策は、再試行することです。
  • ECONNABORTED:103、ソフトウェアによる接続の中止理由は、サービスとクライアントプロセスがTCP接続の「スリーウェイハンドシェイク」を完了した後、クライアントTCPがRST(リセット)セクションを送信したためです。サービスプロセスの観点から、この接続はTCPによってキューに入れられ、サービスプロセスがacceptを呼び出すのを待っている間にRSTが到着しました。POSIXは、この時点でのerrno値はECONNABORTEDでなければならないと規定しています。解決策は無視され、再度受け入れられます。
  • EINTR:4、システムコールの中断理由は、読み取りまたは書き込み時にシステム信号が中断されるためです。解決策は、読み取りと書き込みを継続することです。
  • EPROTO:71、プロトコルエラー原因はプロトコルエラーです。解決策は無視されます。
  • EPERM:1、操作は許可されていません操作は許可されていません。解決策は無視されます。
  • EMFILE:24、開いているファイルが多すぎます開いているファイルが多すぎます解決策は無視されます

おすすめ

転載: blog.csdn.net/u014608280/article/details/85211190