775

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

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

システムはSO_REUSEPORTこれ以上制限されていませんか?

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

4

2 に答える 2

1922

ポータビリティの素晴らしい世界へようこそ...というか、それがないのです。これら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つのソケットを送信元アドレスと送信元ポートの同じ組み合わせにバインドすることはできません。送信元ポートが異なる限り、送信元アドレスは実際には無関係です。が当てはまる場合でも、にバインドsocketAすることは常に可能です。たとえば、FTPサーバープログラムに属し、別のFTPサーバープログラムにバインドされており、にバインドされている場合、両方のバインドが成功します。ただし、ソケットはローカルで「任意のアドレス」にバインドされる可能性があることに注意してください。ソケットがにバインドされている場合、既存のすべてのローカルアドレスに同時にバインドされます。その場合、バインドしようとしている特定のIPアドレスに関係なく、他のソケットをポートにバインドすることはできません。ipA:portAsocketBipB:portBipA != ipBportA == portBsocketA192.168.0.1:21socketB10.0.0.1:210.0.0.0:21210.0.0.0既存のすべてのローカルIPアドレスと競合します。

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

BSD

SO_REUSEADDR

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

がないと、0.0.0.0は「任意のローカルIPアドレス」を意味するため、へSO_REUSEADDRのバインドとその後のバインドは失敗します(エラーが発生します)。したがって、すべてのローカルIPアドレスがこのソケットで使用されていると見なされ、これにはも含まれます。とは完全に同じアドレスではないため、1つはすべてのローカルアドレスのワイルドカードであり、もう1つは非常に特定のローカルアドレスです。上記のステートメントは、バインドされている順序に関係なく当てはまることに注意してください。それがなければ常に失敗し、それがあれば常に成功します。socketA0.0.0.0:21socketB192.168.0.1:21EADDRINUSE192.168.0.1SO_REUSEADDR0.0.0.0192.168.0.1socketAsocketBSO_REUSEADDRSO_REUSEADDR

より良い概要を提供するために、ここに表を作成し、考えられるすべての組み合わせをリストしてみましょう。

SO_REUSEADDRsocketAsocketB結果
-------------------------------------------------- -------------------
  オン/オフ192.168.0.1:21192.168.0.1:21エラー(EADDRINUSE)
  オン/オフ192.168.0.1:2110.0.0.1:21OK
  オン/オフ10.0.0.1:21 192.168.0.1:21 OK
   オフ0.0.0.0:21192.168.1.0:21エラー(EADDRINUSE)
   オフ192.168.1.0:210.0.0.0:21エラー(EADDRINUSE)
   オン0.0.0.0:21192.168.1.0:21OK
   オン192.168.1.0:210.0.0.0:21OK
  オン/オフ0.0.0.0:210.0.0.0:21エラー(EADDRINUSE)

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

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

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

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

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

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

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_REUSEPORTSO_REUSEADDR

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

Connect()EADDRINUSEを返しますか?

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

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

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

マルチキャストアドレス

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

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


FreeBSD / OpenBSD / NetBSD

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


macOS(MacOS X)

本質的に、macOSは「ダーウィン」という名前のBSDスタイルのUNIXであり、BSDコード(BSD 4.3)のかなり遅いフォークに基づいており、後で(当時の)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存在していました。このオプションは、2つの重要な例外を除いて、BSDとほぼ同じように動作します。

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

  2. 2番目の例外は、クライアントソケットの場合、SO_REUSEPORTバインドされる前に両方にこのフラグが設定されている限り、このオプションはBSDの場合とまったく同じように動作することです。これを許可する理由は、複数のソケットをさまざまなプロトコルの同じUDPソケットアドレスに正確にバインドできることが重要であり、SO_REUSEPORT3.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_REUSEPORTSO_REUSEADDRWindowsのソケットでの設定は、BSDのソケットでの設定と同じように動作しますが、1つの例外がありますSO_REUSEPORTSO_REUSEADDR

Windows 2003より前では、他のソケットがバインドされたときにこのオプションが設定されていなかった場合でも、のソケットはSO_REUSEADDR、すでにバインドされたソケットとまったく同じ送信元アドレスとポートに常にバインドされていました。この動作により、アプリケーションは別のアプリケーションの接続されたポートを「盗む」ことができました。言うまでもなく、これにはセキュリティに大きな影響があります。

Microsoftはそれを認識し、別の重要なソケットオプションを追加しましたSO_EXCLUSIVEADDRUSE。ソケットに設定SO_EXCLUSIVEADDRUSEすると、バインドが成功した場合、送信元アドレスとポートの組み合わせはこのソケットによって排他的に所有され、設定されている場合でも、他のソケットはそれらにバインドできませんSO_REUSEADDR

このデフォルトの動作はWindows2003で最初に変更され、Microsoftはこれを「拡張ソケットセキュリティ」(他のすべての主要なオペレーティングシステムでデフォルトとなる動作の面白い名前)と呼んでいます。詳細については、このページをご覧ください。3つの表があります。1つ目は従来の動作(互換モードを使用している場合でも使用中です!)、2つ目bind()は同じユーザーが呼び出しを行ったときのWindows 2003以降の動作、3つ目はbind()呼び出しはさまざまなユーザーによって行われます。


Solaris

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

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


その他のシステム

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

コードの構築に必要なのは、ビットPOSIX API(ネットワーク部分用)とC99コンパイラー(実際には、ほとんどの非C99コンパイラーは、提供されている限り機能しますinttypes.hstdbool.hたとえばgcc、完全なC99サポートを提供するずっと前にサポートされています) 。

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

それはあなたが考えることができるすべての可能な組み合わせをテストします:

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

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

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

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

于 2013-01-17T21:45:44.917 に答える