linux - ソケットオプションSO_REUSEADDRとSO_REUSEPORTはどう違うのですか? 彼らはすべての主要なオペレーティングシステムで同じ意味ですか?



windows sockets (1)

ソケットオプションSO_REUSEADDRSO_REUSEPORTman pagesとプログラマーのドキュメントは、オペレーティングシステムによって異なり、多くの場合非常に混乱します。 一部のオペレーティングシステムでは、 SO_REUSEPORTオプションもありません。 WEBにはこの件に関する矛盾した情報がたくさんありますが、特定のオペレーティングシステムの1つのソケット実装に関してのみ真実である情報を見つけることができます。

SO_REUSEADDRSO_REUSEADDRとはどのくらい正確ですか?

SO_REUSEPORTないシステムは制限されていますか?

そして、別のオペレーティングシステムでどちらかを使用すると、予想される動作はどうなりますか?


ポータビリティの素晴らしい世界へようこそ。 これらの2つのオプションを詳細に分析し、異なるオペレーティングシステムがそれらをどのように扱うかを詳しく見ていく前に、BSDソケットの実装はすべてのソケット実装の母であることに注意してください。 基本的には、他のすべてのシステムは、ある時点(または少なくともそのインタフェース)でBSDソケット実装をコピーしてから、それを独自に進化させ始めました。 もちろん、BSDソケットの実装も同時に進化しました。したがって、後でそれをコピーしたシステムには、それを先にコピーしたシステムでは欠けていた機能があります。 BSDソケットの実装を理解することは、他のすべてのソケット実装を理解するための鍵です。したがって、BSDシステム用のコードを書いても気にしなくても読んでください。

これら2つのオプションを見る前に知っておくべき基本がいくつかあります。 TCP / UDP接続は、5つの値からなるタプルによって識別されます。

{<protocol>, <src addr>, <src port>, <dest addr>, <dest port>}

これらの値の固有の組み合わせによって、接続が識別されます。 その結果、2つの接続が同じ5つの値を持つことはできません。そうしないと、システムはこれらの接続をもう区別できなくなります。

ソケットのプロトコルは、ソケットがsocket()関数で作成されたときに設定されます。 送信元アドレスとポートはbind()関数で設定されます。 宛先アドレスとポートはconnect()関数で設定されます。 UDPはコネクションレスプロトコルなので、UDPソケットは接続せずに使用できます。 しかし、それらを接続することは許されており、コードや一般的なアプリケーション設計に非常に有利な場合もあります。 コネクションレスモードでは、データが最初に送信されたときに明示的にバインドされなかったUDPソケットは、通常、システムによって自動的にバインドされます。 バインドされていないTCPソケットにも同じことが言えます。接続される前に自動的にバインドされます。

明示的にソケットをバインドすると、それをポート0にバインドすることができます0これは "任意のポート"を意味します。 ソケットは実際には既存のすべてのポートにバインドできないので、システムは特定のポート自体を選択する必要があります(通常はOSポート固有の事前定義された範囲から選択します)。 送信元アドレスには、「任意のアドレス」(IPv4の場合は0.0.0.0 、IPv6の場合は:: :)と同様のワイルドカードが存在します。 ポートの場合とは異なり、ソケットは実際には「すべてのローカルインタフェースのすべての送信元IPアドレス」を意味する「任意のアドレス」にバインドできます。 後でソケットが接続されている場合、ソケットは接続できず、同時に任意のローカルIPアドレスにバインドされるため、システムは特定の送信元IPアドレスを選択する必要があります。 宛先アドレスとルーティングテーブルの内容に応じて、システムは適切な送信元アドレスを選択し、「任意の」バインディングを選択した送信元IPアドレスへのバインディングに置き換えます。

デフォルトでは、送信元アドレスと送信元ポートの同じ組み合わせに2つのソケットをバインドすることはできません。 送信元ポートが異なる限り、送信元アドレスは実際には関係ありません。 socketAA:XsocketBB:YにバインドしsocketA 。ここで、 ABはアドレスであり、 XYはポートX != Yが成り立つ限り、常に可能です。 しかし、 X == Yであっても、 A != Bが成り立つ限り、バインディングは可能です。 たとえば、 socketAはFTPサーバープログラムに属し、 192.168.0.1:21 : socketAにバインドされ、 socketBは別のFTPサーバープログラムに属し、 10.0.0.1:21 : socketAにバインドされています。両方のバインディングが成功します。 ただし、ソケットはローカルに「任意のアドレス」にバインドされている可能性があることに注意してください。 ソケットが0.0.0.0:21にバインドされている場合は、既存のすべてのローカルアドレスに同時にバインドされます。その場合、バインドしようとする特定のIPアドレスに関係なく、他のソケットはポート21にバインドできません。 0.0.0.0既存のすべてのローカルIPアドレスと競合します。

これまでに言われたことは、すべての主要なオペレーティングシステムでほぼ同等です。 アドレスの再利用が始まると、OS固有のものが始まります。 上で述べたように、すべてのソケット実装の母ですから、BSDから始めます。

BSD

SO_REUSEADDR

バインドする前にソケットでSO_REUSEADDRが有効になっている場合、ソースアドレスとポートのまったく同じ組み合わせにバインドされた別のソケットとの競合がない限り、ソケットは正常にバインドできます。 あなたは以前とは違うものがどういうのだろうか? キーワードは「正確に」です。 SO_REUSEADDRは、競合の検索時にワイルドカードアドレス(「任意のIPアドレス」)の処理方法を主に変更します。

SO_REUSEADDRなしでSO_REUSEADDRにバインドし、 socketB192.168.0.1:21バインドするとエラー(エラーEADDRINUSE )が発生しますEADDRINUSEは「任意のローカルIPアドレス」を意味するため、すべてのローカルIPアドレスが使用中と見なされるこのソケットには192.168.0.1も含まれています。 SO_REUSEADDRでは、 0.0.0.0192.168.0.1まったく同じアドレスではないため、1つはすべてのローカルアドレスのワイルドカードであり、もう1つは非常に固有のローカルアドレスです。 socketAsocketBどちらの順序でsocketAれているかにかかわらず、上記のステートメントは真であることに注意してください。 SO_REUSEADDRば常に失敗し、 SO_REUSEADDRは常に成功します。

より良い概観を得るために、ここでテーブルを作成し、可能なすべての組み合わせをリストアップしましょう:

SO_REUSEADDR       socketA        socketB       Result
---------------------------------------------------------------------
  ON/OFF       192.168.0.1:21   192.168.0.1:21    Error (EADDRINUSE)
  ON/OFF       192.168.0.1:21      10.0.0.1:21    OK
  ON/OFF          10.0.0.1:21   192.168.0.1:21    OK
   OFF             0.0.0.0:21   192.168.1.0:21    Error (EADDRINUSE)
   OFF         192.168.1.0:21       0.0.0.0:21    Error (EADDRINUSE)
   ON              0.0.0.0:21   192.168.1.0:21    OK
   ON          192.168.1.0:21       0.0.0.0:21    OK
  ON/OFF           0.0.0.0:21       0.0.0.0:21    Error (EADDRINUSE)

上記の表は、 socketAがすでにsocketAのアドレスにバインドされていて、 socketBが作成され、 SO_REUSEADDR設定されているかSO_REUSEADDRかをSO_REUSEADDR 、最後にsocketBアドレスにバインドされていることをsocketBます。 ResultsocketBのバインド操作の結果です。 最初の列にON/OFFと表示されている場合、 SO_REUSEADDRの値はSO_REUSEADDRとは無関係です。

さて、 SO_REUSEADDRはワイルドカードアドレスに影響を与えます。 それだけでは効果がありません。 もう1つのよく知られた効果があります。これは、ほとんどの人がサーバープログラムでSO_REUSEADDRを最初に使用する理由です。 このオプションのもう1つの重要な使い方については、TCPプロトコルがどのように機能するかをより深く見なければなりません。

ソケットには送信バッファがあり、 send()関数の呼び出しが成功した場合、要求されたデータが実際に実際に送信されたことを意味するわけではなく、データが送信バッファに追加されたことを意味します。 UDPソケットの場合、データは通常すぐに送信されますが、すぐには送信されませんが、TCPソケットの場合、送信バッファにデータを追加してからTCP実装で実際にデータを送信するまでに比較的長い遅延があります。 その結果、TCPソケットを閉じるとまだ送信されていない送信バッファに保留中のデータが残っている可能性がありますが、コードはsend()呼び出しが成功したsend()と見なします。 TCP実装がリクエストですぐにソケットを閉じていた場合、このデータはすべて失われてしまい、あなたのコードはそれについても知らないでしょう。 TCPは信頼性の高いプロトコルであると言われています。 そのため、まだ送信するデータがあるソケットは、閉じるときにTIME_WAITという状態になります。 その状態では、保留中のすべてのデータが正常に送信されるまで、またはタイムアウトが発生するまで待機します。この場合、ソケットは強制的に閉じられます。

まだ送信データが保留されているかどうかにかかわらず、カーネルがソケットを閉じるまでに待つ時間は、 リンガ時間と呼ばれます。 Linger Timeは、ほとんどのシステムでグローバルに設定可能で、デフォルトではかなり長い(2分は多くのシステムで共通の値です)。 これはソケットオプションSO_LINGERを使用してソケットごとに設定することもできます。ソケットオプションSO_LINGERを使用すると、タイムアウトを短くしたり長くしたり、完全に無効にしたりすることができます。 しかし、完全に無効にすることは非常に悪い考えです。なぜなら、TCPソケットを正常に閉じることはやや複雑なプロセスであり、パケットを2つ送り返すこと(パケットが失われた場合にそれらのパケットを再送するだけでなく) Linger Timeによっても制限されています。 残念ならない設定を無効にすると、ソケットは保留中のデータを失うだけでなく、通常は推奨されていない、常に優しくなく強制的に閉じられます。 TCP接続が正常に閉じられる方法の詳細は、この回答の範囲外です。詳細については、 このページをご覧くださいSO_LINGERSO_LINGERせることができなくても、ソケットを明示的に閉じずにプロセスが終了しても、設定したものを無視してBSD(およびおそらく他のシステム)が残ってしまいます。 例えば、コードが単にexit() (ちょっとした単純なサーバープログラムでよく見られるexit()呼び出した場合や、プロセスがシグナルによって殺された場合(これは、不正なメモリアクセスのためにクラッシュする可能性を含みます) ソケットがどんな状況下でも決して止まらないようにするためにできることは何もありません。

問題は、システムがTIME_WAIT状態のソケットをどのように扱うのでしょうか? SO_REUSEADDRが設定されていない場合、 TIME_WAIT状態のソケットは送信元アドレスとポートにバインドされていると見なされ、新しいソケットを同じアドレスとポートにバインドしようとすると、ソケットが実際に閉じられるまで失敗します。設定されたリンガー時間限り。 したがって、ソケットのソースアドレスを閉じる直後に再バインドできるとは思わないでください。 ほとんどの場合、これは失敗します。 しかし、バインドしようとしているソケットにSO_REUSEADDRが設定されている場合、 TIME_WAIT状態の同じアドレスとポートにバインドされている別のソケットは、すでに "半分が死んでいる"後に無視され、ソケットはまったく同じアドレスにバインドできます問題なく。 その場合、他のソケットがまったく同じアドレスとポートを持つことはありません。 TIME_WAIT状態のソケットとまったく同じアドレスとポートにバインドすると、予期せぬ、通常は望ましくない副作用が発生する可能性があることに注意してください。幸いにもそれらの副作用は実際にはまれです。

SO_REUSEADDRについて知ってSO_REUSEADDRべき1つの最後のことがあります。 バインドしたいソケットがアドレスの再利用を有効にしている限り、上に書いたものはすべて動作します。 すでにバインドされている、またはTIME_WAIT状態にあるもう1つのソケットには、バインド時にこのフラグが設定されている必要はありません。 バインドが成功するか失敗するかを決定するコードは、 bind()呼び出しに送られたソケットのSO_REUSEADDRフラグを検査し、検査された他のすべてのソケットについて検査します。このフラグは調べません。

SO_REUSEPORT

SO_REUSEPORTは、ほとんどの人がSO_REUSEADDRを期待するものです。 基本的に、 SO_REUSEPORTは、バインドされる前にすべての以前のバインドされたソケットにもSO_REUSEPORT設定されている限り、任意の数のソケットを正確に同じソースアドレスとポートにバインドできます。 アドレスとポートにバインドされた最初のソケットにSO_REUSEPORT設定されていない場合、最初のソケットがバインディングを解放するまで、この他のソケットにSO_REUSEPORT設定されているかどうかにかかわらず、再び。 SO_REUESADDRの場合とは異なり、 SO_REUSEPORTを処理するコードは、現在バインドされているソケットにSO_REUSEPORT設定されていることを検証するだけでなく、競合するアドレスとポートを持つソケットがSO_REUSEPORTされたときにSO_REUSEPORT設定したことを確認します。

SO_REUSEPORTSO_REUSEPORT意味しません。 つまり、ソケットにSO_REUSEPORT設定されていない場合、 SO_REUSEPORT設定されているときにSO_REUSEPORT設定されていない場合、バインドは失敗しますが、他のソケットが既に存在する場合は失敗します。 TIME_WAIT状態になります。 TIME_WAIT状態で別のソケットと同じアドレスとポートにソケットをバインドできるようにするには、そのソケットにSO_REUSEADDRを設定するか、 SO_REUSEADDRをバインドする前に両方のソケットに設定する必要があります。 もちろん、 SO_REUSEPORTSO_REUSEADDR両方をソケットに設定することは許可されています。

SO_REUSEPORTについてはSO_REUSEPORTより後で追加されたこと以外はそれほど多くはありません。 SO_REUSEADDR 、このオプションが追加される前にBSDコードをforkした他のシステムの多くのソケット実装ではそれを見つけることができないからです。このオプションの前に2つのソケットをBSDの全く同じソケットアドレスにバインドする方法はありませんでした。

Connect()EADDRINUSEを返しますか?

ほとんどの人は、 bind()がエラーEADDRINUSEで失敗する可能性があることを知っていますが、アドレスの再利用で再生を開始すると、 connect()がそのエラーで失敗connect()という奇妙な状況に陥る可能性があります。 どうすればいいの? リモートアドレスは、接続がソケットに追加された後、どのように使用されているのでしょうか? 複数のソケットを正確に同じリモートアドレスに接続することはこれまで一度も問題にはなりませんでしたが、ここで何が問題になっていますか?

私が返信の一番上で言ったように、接続は5つの値からなるタプルによって定義されます。覚えていますか? そして、私はまた、これらの5つの値がユニークでなければならないと言っています。そうでなければ、システムはもう2つの接続を区別できません。 アドレスの再利用では、同じプロトコルの2つのソケットを同じ送信元アドレスとポートにバインドできます。 これは、これらの5つの値のうちの3つが、これらの2つのソケットですでに同じであることを意味します。 これらのソケットの両方を同じ宛先アドレスとポートに接続しようとすると、タプルが完全に同一である2つの接続ソケットが作成されます。 これは少なくともTCP接続では機能しません(UDP接続は実際には接続できません)。 2つの接続のいずれか1つでデータが到着した場合、システムはデータがどの接続に属しているかを知ることができませんでした。 どちらの接続でも、宛先アドレスまたは宛先ポートは少なくとも異なる必要があります。そのため、着信データがどの接続に属しているかを識別するのに問題はありません。

したがって、同じプロトコルの2つのソケットを同じ送信元アドレスとポートにバインドし、それらを同じ宛先アドレスとポートにconnect()しようとすると、 connect()は接続しようとする2番目のソケットのエラーEADDRINUSEで実際に失敗し、これは、5つの値の同じタプルを持つソケットがすでに接続されていることを意味します。

マルチキャストアドレス

ほとんどの人はマルチキャストアドレスが存在するという事実を無視しますが、それらは存在します。 ユニキャストアドレスは1対1通信に使用されますが、マルチキャストアドレスは1対多の通信に使用されます。 ほとんどの人は、IPv6について学んだときにマルチキャストアドレスを認識しましたが、この機能は公衆インターネットでは決して広く使われていませんでしたが、IPv4にも存在していました。

SO_REUSEADDRの意味は、複数のソケットがソースマルチキャストアドレスとポートのまったく同じ組み合わせにバインドできるようにするため、マルチキャストアドレスSO_REUSEADDR変更されます。 つまり、マルチキャストアドレスSO_REUSEADDRは、ユニキャストアドレスのSO_REUSEPORTと同じように動作します。 実際には、コードはSO_REUSEADDRSO_REUSEPORTをマルチキャストアドレスと同じように扱います。つまり、 SO_REUSEPORTはすべてのマルチキャストアドレスに対してSO_REUSEADDRを意味します。


FreeBSD / OpenBSD / NetBSD

これらはすべてオリジナルのBSDコードの遅いフォークであるため、3つすべてがBSDと同じオプションを提供し、BSDと同じように動作します。


macOS(MacOS X)

その中心にあるmacOSは、ちょっと遅れたBSDコード(BSD 4.3)をベースにした " ダーウィン "という名前のBSDスタイルのUNIXで、後で(今の時点で)FreeBSDと再同期していますMacOS 10.3リリース用の5つのコードベースを提供しています。その結果、アップルは完全なPOSIX準拠(macOSはPOSIX認定)となりました。 コア( " マッハ ")にマイクロカーネルがあるにもかかわらず、カーネルの残りの部分( " XNU ")は基本的にBSDカーネルに過ぎないため、macOSはBSDと同じオプションを提供し、BSDと同じように動作します。

iOS / watchOS / tvOS

iOSは、わずかに修正され、調整されたカーネルを持つmacOSフォークであり、ユーザースペースツールセットと多少異なるデフォルトフレームワークセットが削除されています。 watchOSとtvOSはiOSフォークであり、それはさらに落とされています(特にwatchOS)。 私の最善の知識のために、彼らはすべてmacOSとまったく同じように動作します。


Linux

Linux <3.9

Linux 3.9以前は、オプションSO_REUSEADDRのみが存在していました。 このオプションは、BSDとほぼ同じように動作しますが、2つの重要な例外があります。

  1. リスニング(サーバー)TCPソケットが特定のポートにバインドされているSO_REUSEADDRSO_REUSEADDRオプションは、そのポートをターゲットとするすべてのソケットでは完全に無視されます。 2番目のソケットを同じポートにバインドすることは、 SO_REUSEADDR設定せずにBSDでも可能だった場合にのみ可能です。 たとえば、ワイルドカードアドレスにバインドできず、より具体的なアドレスにバインドすることはできませんSO_REUSEADDRを設定すると、BSDで両方とも可能です。 あなたができることは、常に許可されているように、同じポートと2つの異なる非ワイルドカードアドレスにバインドできることです。 この側面では、LinuxはBSDよりも制限的です。

  2. 2つ目の例外は、クライアントソケットの場合、このオプションは、バインドされる前にこのフラグが設定されていれば、BSDのSO_REUSEPORTとまったく同じように動作します。 これを可能にする理由は、複数のソケットをさまざまなプロトコルのために同じUDPソケットアドレスに正確にバインドできることが重要であり、以前は3.9よりもSO_REUSEPORTがないため、 SO_REUSEPORTの動作が変更されてそのギャップ。 この側面では、LinuxはBSDよりも制限が少ない。

Linux> = 3.9

Linux 3.9では、 SO_REUSEPORTオプションもLinuxに追加されました。 このオプションはBSDのオプションとまったく同じように動作し、すべてのソケットにバインドする前にこのオプションが設定されている限り、まったく同じアドレスとポート番号にバインドすることができます。

それでも、他のシステムでSO_REUSEPORTには2つの違いがあります。

  1. 「ポートハイジャック」を防ぐために、1つの特別な制限があります。同じアドレスとポートの組み合わせを共有したいすべてのソケットは、同じ実効ユーザーIDを共有するプロセスに属していなければなりません! したがって、あるユーザーは別のユーザーのポートを "盗む"ことはできません。 これは、欠落しているSO_EXCLBIND / SO_EXCLUSIVEADDRUSEフラグをいくらか補うための特別な魔法です。

  2. さらに、カーネルは、他のオペレーティングシステムにはないSO_REUSEPORTソケットの「特別な魔法」を実行しますSO_REUSEPORTソケットの場合、TCPリスニングソケットのためにデータグラムを均等に分配しようとしますが、着信接続要求同じアドレスとポートの組み合わせを共有するすべてのソケットで均等にaccept()を実行します。 したがって、アプリケーションは複数の子プロセスで同じポートを簡単に開き、 SO_REUSEPORTを使用して非常に安価なロードバランシングを取得できます。


アンドロイド

Androidシステム全体はほとんどのLinuxディストリビューションとは多少異なりますが、そのコアはやや修正されたLinuxカーネルで動作するため、Linuxに適用されるすべてのものがAndroidにも適用されるはずです。


Windows

WindowsはSO_REUSEADDRオプションのみを認識し、 SO_REUSEADDRはありませSO_REUSEPORT 。 ソケットのSO_REUSEADDRは、BSDのソケットでSO_REUSEPORTSO_REUSEADDRを設定するのと同じように動作しますが、 SO_REUSEADDR のソケットは、他のソケットが行った場合でも常にバインドされたソケットと同じソースアドレスとポートにバインドできますバインドされたときにこのオプションが設定されていません 。 この動作は、アプリケーションが別のアプリケーションの接続されたポートを "盗む"ことができるため、やや危険です。 言うまでもなく、これはセキュリティに大きな影響を与える可能性があります。 マイクロソフトではこれが問題である可能性があることを認識し、別のソケットオプションSO_EXCLUSIVEADDRUSEを追加しました。 ソケットにSO_EXCLUSIVEADDRUSEを設定すると、バインディングが成功すると、送信元アドレスとポートの組み合わせがこのソケットによって排他的に所有され、 SO_REUSEADDR設定されていても、他のソケットはバインドできません。

SO_REUSEADDRSO_EXCLUSIVEADDRUSEフラグがどのようにWindows上で動作するかについての詳細は、バインディング/再バインディングにどのように影響するのか、マイクロソフトは親切にも私のテーブルに似たテーブルをその応答の先頭近くに提供しました。 このページに行って少し下にスクロールしてください 。 実際には3つのテーブルがあり、最初のものは古い動作(Windows 2003以前)、2つ目は動作(Windows 2003以降)、3つ目はWindows 2003以降の動作の変化を示しています。異なるユーザーによって作成されます。


Solaris

SolarisはSunOSの後継です。 SunOSはもともとBSDのフォークをベースにしていましたが、SunOS 5以降はSVR4のフォークをベースにしていましたが、SVR4はBSD、System V、Xenixのマージであるため、SolarisもBSDフォークです。かなり初期のものです。 その結果、SolarisはSO_REUSEADDRしか認識しませんSO_REUSEPORTはありませSO_REUSEPORTSO_REUSEADDRはBSDとほぼ同じように動作します。 私が知る限り、SolarisではSO_REUSEPORTと同じ動作をする方法がありません。つまり、2つのソケットをまったく同じアドレスとポートにバインドすることはできません。

Windowsと同様に、Solarisにはソケットに排他的なバインディングを与えるオプションがあります。 このオプションの名前はSO_EXCLBINDです。 ソケットをバインドする前にこのオプションをソケットに設定すると、2つのソケットがアドレス競合をテストされている場合、別のソケットにSO_REUSEADDRを設定しても効果はありません。 たとえば、 socketAがワイルドカードアドレスにバインドされ、 socketBSO_REUSEADDR有効にし、ワイルドカードではないアドレスとsocketBと同じポートにバインドされている場合、 SO_EXCLBIND有効になっていない限り、このバインドは通常成功します。 SO_REUSEADDRフラグ。


その他のシステム

あなたのシステムが上にリストされていない場合は、システムがこれらの2つのオプションをどのように扱うかを調べるための小さなテストプログラムを書きました。 また、私の結果が間違っていると思われる場合は、最初にそのプログラムを実行してからコメントを投稿し、偽の主張をする可能性があります。

コードをビルドするために必要なものは、POSIX API(ネットワーク部分用)とC99コンパイラです(実際にはほとんどのC99コンパイラは、 inttypes.hstdbool.hを提供する限り動作します。 C99の完全なサポートを提供するよりずっと前)。

プログラムが実行する必要があるのは、システムの少なくとも1つのインターフェイス(ローカルインターフェイス以外)にIPアドレスが割り当てられており、そのインターフェイスを使用する既定のルートが設定されていることです。 プログラムはそのIPアドレスを収集し、それを第2の「特定のアドレス」として使用します。

考えられるすべての組み合わせをテストします:

  • TCPおよびUDPプロトコル
  • 通常のソケット、リッスン(サーバー)ソケット、マルチキャストソケット
  • ソケット1、ソケット2、または両方のソケットにSO_REUSEADDR設定
  • SO_REUSEPORT 、socket2、または両方のソケットに設定されたSO_REUSEPORT
  • 0.0.0.0 (ワイルドカード)、 127.0.0.1 (特定のアドレス)、およびプライマリインターフェイスで見つかった2番目の特定のアドレス(マルチキャストの場合は、すべてのテストで224.1.2.3

結果を素敵なテーブルに表示します。 SO_REUSEPORT知らないシステムでも動作します。この場合、このオプションは単にテストされません。

プログラムが簡単にテストできないのは、 SO_REUSEADDRがソケットをTIME_WAIT状態で動作させる方法SO_REUSEADDR 。ソケットを強制的にその状態に保つのは非常にSO_REUSEADDRです。 幸いなことに、ほとんどのオペレーティングシステムはここでBSDのように振る舞うだけであると思われ、プログラマーはその状態の存在を単純に無視することができます。

ここにコードがあります (私はそれを含めることはできません、答えはサイズ制限があり、コードはこの応答を制限を超えて押します)。





portability