SO_REUSEADDRとSO_REUSEPORTの違いは何ですか?


663

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

では、正確にはどのようにSO_REUSEADDR違うのですSO_REUSEPORTか?

SO_REUSEPORT制限のないシステムはありますか?

また、異なるオペレーティングシステムでどちらかを使用した場合、予想される動作は正確には何ですか?

回答:


1616

移植性の素晴らしい世界へようこそ...むしろそれの欠如。これら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ソケットは、バインドされていないUDPソケットが(応答)データを受信できないため、通常、システムによって自動的にバインドされます。バインドされていないTCPソケットについても同様です。接続される前に自動的にバインドされます。

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

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

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

BSD

SO_REUSEADDR

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

せずにSO_REUSEADDR結合、socketA0.0.0.0:21して、結合socketBする192.168.0.1:21(エラーで失敗しますEADDRINUSE)、0.0.0.0手段「任意のローカルIPアドレス」以来、したがって、すべてのローカルIPアドレスがこのソケットで使用されているとみなされ、これは、192.168.0.1あまりにも、。でSO_REUSEADDR、それがあるため、成功する0.0.0.0192.168.0.1されている正確ではない同じアドレス、一つは、すべてのローカルアドレスにはワイルドカードであり、もう一つは非常に特定のローカルアドレスです。上記のステートメントは、どの順序socketAsocketBバインドされているかに関係なく当てはまることに注意してください。SO_REUSEADDRそれなしでは常に失敗し、SO_REUSEADDR常に成功します。

概要をわかりやすくするために、ここに表を作成し、可能なすべての組み合わせをリストしてみましょう。

SO_REUSEADDR socketA socketB結果
-------------------------------------------------- -------------------
  ON / OFF 192.168.0.1:21 192.168.0.1:21エラー(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
   オフ0.0.0.0:21 192.168.1.0:21エラー(EADDRINUSE)
   オフ192.168.1.0:21 0.0.0.0:21エラー(EADDRINUSE)
   オン0.0.0.0:21 192.168.1.0:21 OK
   オン192.168.1.0:21 0.0.0.0:21 OK
  ON / OFF 0.0.0.0:21 0.0.0.0:21エラー(EADDRINUSE)

上の表は、socketAがに指定されたアドレスに既に正常にバインドされていることを前提としていますsocketA。その後socketB、作成され、SO_REUSEADDR設定されるかどうかにかかわらず、最後にに指定されたアドレスにバインドされsocketBます。Resultのバインド操作の結果ですsocketB。最初の列がON/OFFである場合、の値はSO_REUSEADDR結果とは無関係です。

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

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

カーネルがソケットを閉じるまでに待機する時間は、まだデータが処理中かどうかに関係なく、リンガータイムと呼ばれます。リンガー時間(2分あなたは多くのシステム上で見つける共通の値である)かなり長いほとんどのシステムで、デフォルトでは、グローバル設定可能です。またSO_LINGER、タイムアウトを短くしたり長くしたり、完全に無効にするために使用できるソケットオプションを使用して、ソケットごとに構成することもできます。ただし、TCPソケットを正常に閉じることは少し複雑なプロセスであり、2、3のパケットの送信と送信(および失われた場合に備えてこれらのパケットを再送信する)とこの全体のクローズプロセスが含まれるため、完全に無効にすることは非常に悪い考えです。リンガータイムによっても制限されます。残存を無効にすると、ソケットは処理中のデータを失うだけでなく、正常にではなく常に強制的に閉じられる可能性があります。これは通常は推奨されません。TCP接続が正常に閉じられる方法の詳細は、この回答の範囲を超えています。詳しく知りたい場合は、このページをご覧になることをお勧めします。またSO_LINGER、で残留を無効にした場合でも、明示的にソケットを閉じずにプロセスが停止すると、BSD(および場合によっては他のシステム)は残留し、設定した内容を無視します。これは、たとえば、コードが単に呼び出す場合に発生しますexit()(非常に小さく単純なサーバープログラムではかなり一般的です)またはプロセスがシグナルによって強制終了されます(これには、不正なメモリアクセスが原因で単にクラッシュする可能性が含まれます)。したがって、すべての状況でソケットが残存しないようにするためにできることはありません。

問題は、システムが状態のソケットをどのように処理するTIME_WAITかです。SO_REUSEADDRが設定されていない場合、状態のソケットはTIME_WAITまだ送信元アドレスとポートにバインドされていると見なされ、新しいソケットを同じアドレスとポートにバインドしようとすると、ソケットが実際に閉じられるまで失敗します。設定されたリンガータイムとして。したがって、ソケットを閉じた直後にソケットのソースアドレスを再バインドできるとは期待しないでください。ほとんどの場合、これは失敗します。ただし、SO_REUSEADDRバインドしようとしているソケットにが設定されている場合、同じアドレスとポートにバインドされている別のソケットTIME_WAITすべてがすでに「半分死んでいる」後は無視​​され、ソケットはまったく同じアドレスに問題なくバインドできます。その場合、他のソケットがまったく同じアドレスとポートを持つ可能性があるという役割はありません。TIME_WAIT状態にある瀕死のソケットとまったく同じアドレスとポートにソケットをバインドすると、他のソケットがまだ「機能している」場合、予期しない、通常は望ましくない副作用が発生する可能性がありますが、これはこの回答の範囲を超えており、幸い、これらの副作用は実際にはかなりまれです。

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

SO_REUSEPORT

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

SO_REUSEPORTは意味しませんSO_REUSEADDR。つまり、SO_REUSEPORTバインドされたときにソケットがSO_REUSEPORT設定されておらず、まったく同じアドレスとポートにバインドされたときに別のソケットが設定されている場合、バインドは失敗しますが、これは予想されますが、他のソケットがすでに停止している場合も失敗します。であるTIME_WAIT状態。ソケットを同じTIME_WAIT状態の別のソケットと同じアドレスとポートにバインドできるようにするには、SO_REUSEADDRそのソケットに設定するか、バインドする前に両方のソケットにSO_REUSEPORT設定しておく必要があります。もちろん、ソケットにSO_REUSEPORTとの両方を設定できSO_REUSEADDRます。

SO_REUSEPORTそれ以降に追加されたこと以外に言うべきことはそれほど多くありません。そのためSO_REUSEADDR、このオプションが追加される前にBSDコードを「フォーク」した他のシステムの多くのソケット実装ではそれが見つかりません。このオプションの前に、BSDで2つのソケットをまったく同じソケットアドレスにバインドする方法。

Connect()EADDRINUSEを返しますか?

ほとんどの人bind()はエラーEADDRINUSEで失敗する可能性があることを知っていますが、アドレスの再利用を試し始めるconnect()と、そのエラーで失敗する奇妙な状況に遭遇する場合もあります。どうすればいいの?どうすれば、connectがソケットに追加したリモートアドレスを既に使用できますか?複数のソケットをまったく同じリモートアドレスに接続することはこれまで問題にならなかったので、ここで何が問題になっていますか?

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

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

マルチキャストアドレス

ほとんどの人は、マルチキャストアドレスが存在するという事実を無視しますが、存在します。ユニキャストアドレスは1対1の通信に使用されますが、マルチキャストアドレスは1対多の通信に使用されます。ほとんどの人はIPv6について知ったときにマルチキャストアドレスに気づきましたが、この機能がパブリックインターネットで広く使用されることはなかったにもかかわらず、IPv4にもマルチキャストアドレスが存在しました。

SO_REUSEADDR複数のソケットを送信元マルチキャストアドレスとポートのまったく同じ組み合わせにバインドできるようにするための、マルチキャストアドレスの変更の意味。つまり、マルチキャストアドレスの場合SO_REUSEADDRSO_REUSEPORT、ユニキャストアドレスの場合とまったく同じように動作します。実際には、コードの扱いSO_REUSEADDRSO_REUSEPORTマルチキャストアドレスのために同一の、あなたはそれを言ってもいい手段がSO_REUSEADDR暗示SO_REUSEPORTすべてのマルチキャストアドレスおよび他の方法でラウンドのために。


FreeBSD / OpenBSD / NetBSD

これらはすべて、元のBSDコードのかなり遅いフォークです。そのため、3つすべてがBSDと同じオプションを提供し、BSDと同じように動作します。


macOS(MacOS X)

中核となるmacOSは、BSDコード(BSD 4.3)の比較的遅いフォークに基づいた、「Darwin」という名前のBSDスタイルのUNIX であり、後で(現時点では)FreeBSDと再同期されましたMac OS 10.3リリース用の5つのコードベース。これにより、AppleはPOSIXに完全に準拠できるようになります(macOSはPOSIX認定済みです)。コア(「Mach」)にマイクロカーネルがあるにもかかわらず、残りのカーネル(「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_REUSEADDRされている限り、そのポートをターゲットとするすべてのソケットのオプションは完全に無視されます。同じポートに2番目のソケットをバインドすることは、BSDでもSO_REUSEADDR設定せずに可能だった場合にのみ可能です。たとえば、ワイルドカードアドレスにバインドしてから、より具体的なアドレスまたはその逆にバインドすることはできません。BSDでは、両方を設定できますSO_REUSEADDR。あなたができることは、常に許可されているので、同じポートと2つの異なる非ワイルドカードアドレスにバインドできることです。この点で、LinuxはBSDよりも制限的です。

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

Linux> = 3.9

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

ただし、SO_REUSEPORT他のシステムとの違いは2つあります。

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

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


アンドロイド

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


ウィンドウズ

WindowsはSO_REUSEADDRオプションのみを認識し、はありませんSO_REUSEPORT。設定SO_REUSEADDRの設定のように、Windowsの振る舞いでソケットにSO_REUSEPORTし、SO_REUSEADDR一つの例外を除いて、BSDソケット上:付きソケットSO_REUSEADDR常にすでにバインドされたソケットとまったく同じ送信元アドレスとポートにバインドすることができ、他のソケットは、このオプションを持っていなかった場合でも、バインドされたときに設定されます。この動作は、アプリケーションが別のアプリケーションの接続されたポートを「盗む」ことを可能にするため、多少危険です。言うまでもなく、これはセキュリティに大きな影響を与える可能性があります。Microsoftは、これが問題になる可能性があることを認識し、別のソケットオプションを追加しましたSO_EXCLUSIVEADDRUSE。設定SO_EXCLUSIVEADDRUSEソケットでは、バインディングが成功した場合、送信元アドレスとポートの組み合わせがこのソケットによって排他的に所有され、他のソケットがそれらにバインドできないことを確認しますSO_REUSEADDR

フラグSO_REUSEADDRSO_EXCLUSIVEADDRUSEWindowsでの動作、バインド/再バインドへの影響の詳細については、Microsoftは、返信の上部にある私のテーブルと同様のテーブルを提供してくれました。このページにアクセスして、少し下にスクロールしてください。場合は、実際に3つのテーブル、最初のショー古い動作(前のWindows 2003)、二番目の動作(Windows 2003およびアップ)と第3の1つのショーのWindows 2003以降でどのように行動に変化があったbind()コールがで作られています別のユーザー。


Solaris

SolarisはSunOSの後継です。SunOSはもともとBSDのフォークに基づいていましたが、SunOS 5以降はSVR4のフォークに基づいていましたが、SVR4はBSD、System V、およびXenixのマージなので、ある程度までSolarisもBSDフォークであり、かなり早いもの。その結果、Solarisは知っているだけでSO_REUSEADDR、ありませんSO_REUSEPORTSO_REUSEADDR振る舞うほとんど同じ、それはBSDの場合と同様。私が知る限りSO_REUSEPORT、Solaris と同じ動作をする方法はありません。つまり、2つのソケットをまったく同じアドレスとポートにバインドすることはできません。

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


その他のシステム

システムが上記にリストされていない場合に備えて、システムがこれら2つのオプションをどのように処理するかを調べるために使用できる小さなテストプログラムを作成しました。また、私の結果が間違っていると思われる場合は、コメントを投稿したり、誤った主張をしたりする前に、まずそのプログラムを実行してください。

コードをビルドするために必要なすべてのビット(ネットワーク部品用)POSIX APIとC99コンパイラである(実際には、ほとんどの非C99コンパイラは限り彼らが提供と同様に動作しますinttypes.hstdbool.h、例えば、gcc長いフルC99のサポートを提供する前に、両方をサポート) 。

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

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

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

結果を素敵な表に出力します。またSO_REUSEPORT、知らないシステムでも機能します。この場合、このオプションはテストされません。

プログラムが簡単にテストできないのは、ソケットをその状態に強制して維持するのが非常に難しいためSO_REUSEADDRTIME_WAIT状態のソケットにどのように作用するかです。幸い、ほとんどのオペレーティングシステムは、ここではBSDのように動作するように見え、ほとんどの場合、プログラマーはその状態の存在を単に無視できます。

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


9
たとえば、「送信元アドレス」は実際には「ローカルアドレス」でなければならず、次の3つのフィールドも同様です。でバインドするとINADDR_ANY、既存のローカルアドレスはバインドされませんが、将来のすべてのアドレスがバインドされます。 listen確かに不可能だと言っていても、プロトコル、ローカルアドレス、ローカルポートがまったく同じソケットが作成されます。
Ben Voigt 2013

9
@Ben SourceおよびDestinationは、IPアドレッシングに使用される公式用語です(私が主に参照しています)。ローカルとリモートは意味がありません。リモートアドレスは実際には「ローカル」アドレスであり、宛先の反対はソースでありローカルではないためです。私はあなたの問題が何であるのかわかりませんINADDR_ANY、それが将来のアドレスにバインドしないとは決して言いませんでした。またlisten、ソケットをまったく作成しないため、文全体が少し奇妙になります。
メッキー2013

7
@Ben新しいアドレスがシステムに追加されると、それは「既存のローカルアドレス」でもあり、存在し始めたばかりです。「現在存在するすべてのローカルアドレスに対して」とは言いませんでした。実際、私はソケットが実際にワイルドカードに実際にバインドされているとさえ言います。つまり、ソケットは、現在、明日、100年後には、このワイルドカードに一致するものにバインドされます。ソースとデスティネーションについても同様ですが、あなたはここでつまらないです。技術的な貢献はありますか?
メッキー2013

8
@メッキー:あなたは本当に「存在する」という言葉は、現在存在しないが将来的に存在するものを含むと思いますか?送信元と宛先は簡単ではありません。着信パケットがソケットに一致すると、パケットの宛先アドレスがソケットの「送信元」アドレスと一致することになりますか?それは間違いであり、あなたはそれを知っています、あなたはすでにソース宛先が反対であると述べました。ソケットのローカルアドレスは、着信パケットの宛先アドレスと照合され、発信パケットの送信アドレスに配置されます。
Ben Voigt 2013

10
@Mecki:「ソケットのローカルアドレスは、発信パケットの送信元アドレスであり、着信パケットの宛先アドレスです」と言った方がはるかに理にかなっています。パケットには、送信元アドレスと宛先アドレスがあります。ホスト、およびホスト上のソケットはサポートしていません。データグラムソケットの場合、両方のピアは同じです。TCPソケットの場合、3ウェイハンドシェイクのため、発信者(クライアント)と応答者(サーバー)がありますが、トラフィックが双方向に流れるため、接続または接続されたソケットに送信元宛先があることを意味しません。
Ben Voigt

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.