web-dev-qa-db-ja.com

2つのアプリケーションが同じポートをlistenできますか?

同じマシン上の2つのアプリケーションを同じポートとIPアドレスにバインドできますか?さらに一歩進めて、一方のアプリが特定のIPからの要求を、もう一方のIPが別のリモートIPからの要求をリッスンできますか? 2つのスレッド(またはフォーク)から開始する1つのアプリケーションで同じような動作を実現できることはわかっていますが、共通点がない2つのアプリケーションでも同じことができますか?

252
nadiv

TCPの場合、いいえ。一度に1つのアプリケーションだけが同じポートをlistenすることができます。 2つのネットワークカードを使用している場合は、1つのアプリケーションに同じポート番号を使用して最初のIPと2番目のIPをリッスンさせることができます。

UDP(Multicast)の場合、複数のアプリケーションが同じポートに加入できます。

226
Chris Dail

はい(TCPの場合)プログラムがそうするように設計されていれば、2つのプログラムに同じソケットでlistenさせることができます。最初のプログラムでソケットが作成されたら、bind()を実行する前に、ソケットにSO_REUSEADDRオプションが設定されていることを確認してください。しかし、これはあなたが望むものではないかもしれません。これは着信TCP接続が両方ではなくプログラムのoneに向けられることである、それでそれは接続を複製しない、それはちょうど2つのプログラムが着信を処理することを許可要求。たとえば、Webサーバーはすべてポート80で待機している複数のプロセスを持ち、O/Sは新しい接続を受け入れる準備ができているプロセスに新しい接続を送信します。

SO_REUSEADDR

既にポートにバインドされているアクティブな待機ソケットがない限り、他のソケットがこのポートに対してbind()を許可します。これにより、クラッシュ後にサーバーを再起動しようとしたときに、 "Address already in use"エラーメッセージを回避することができます。

110
JNewton

原則として、いいえ。

それは石で書かれていません。しかし、それはすべてのAPIの作成方法です。アプリがポートを開き、そのハンドルを取得し、クライアント接続(またはUDPの場合はパケット)が到着すると、OSが(そのハンドルを介して)それを通知します。

OSが2つのアプリが同じポートを開くことを許可している場合、どのアプリがどのポートに通知するのかをどうやって知るのでしょうか。

しかし... ...それを回避する方法があります。

  1. Jed 注記 のように、あなたは 'マスター'プロセスを書くことができます。それはクライアントのリクエストを切り離したいロジックを使って、実際にポートで待機して他の人に通知する唯一のものです。 ]
    • LinuxとBSD(少なくとも)では、ネットワーク関連の基準(おそらくOriginのネットワーク、あるいはいくつかのネットワーク)に従って、パケットを 'visible'ポートから別のポート(アプリがリッスンしているポート)にリダイレクトする 'remapping'ルールを設定できます。単純な形式の負荷分散).
47
Javier

はい。

  1. すべて同じポートにバインドされている複数の待機TCPソケットが、すべて異なるローカルIPアドレスにバインドされている場合、共存できます。クライアントは、必要な方に接続できます。これは0.0.0.0INADDR_ANY)を除外します。

  2. 複数の承認済みソケットを共存させることができ、すべて同じ待機ソケットから受け入れ、すべて待機ソケットと同じローカルポート番号を示します。

  3. すべて同じポートにバインドされた複数のUDPソケットは、(1)と同じ条件ですべて共存することも、バインド前にSO_REUSEADDRオプションが設定されていることもあります。

  4. TCPポートとUDPポートは異なるネームスペースを占有するため、TCPにポートを使用してもUDPへの使用が妨げられることはなく、その逆も同様です。

参照:Stevens&Wright、TCP/IP Illustrated、Volume II。

43
user207421

はいはい。私が覚えている限りでは、カーネルのバージョン3.9から(バージョンではわかりません)以降SO_REUSEPORTのサポートが導入されました。最初のサーバーがソケットをバインドする前にこのオプションを設定している限り、SO_RESUEPORTを使用すると、まったく同じポートとアドレスにバインドできます。

これはTCPUDPの両方で機能します。詳しくはリンクを参照してください。 SO_REUSEPORT

:私の意見では、受け入れられた答えはもはや当てはまりません。

23
piyush

いいえ。一度に1つのアプリケーションしかポートにバインドできません。バインドを強制した場合の動作は不定です。

マルチキャストソケットでは、SO_REUSEADDRが各ソケットのオプションで設定されている限り、複数のアプリケーションが1つのポートにバインドできます。

これを実現するには、すべての接続を受け入れて処理し、それらを同じポートで待機する必要がある2つのアプリケーションに渡します。多くのプロセスが80を監視する必要があるため、これはWebサーバーなどが採用するアプローチです。

これを超えて、私たちは詳細に入っています - あなたはTCPとUDPの両方にタグ付けしました、それはそれですか?また、どのようなプラットフォーム?

18
Jed Smith

1つのアプリケーションが1つのネットワークインターフェースに対して1つのポートをリッスンすることができます。したがって、あなたは持つことができます:

  1. httpdはリモートからアクセス可能なインタフェースをリッスンしています。 192.168.1.1:80
  2. 別のデーモンが127.0.0.1:80をリ​​ッスンしています

使用例としては、ロードバランサまたはプロキシとしてhttpdを使用することが考えられます。

3
SummerBreeze

別の方法は、「本物の」サービスがリッスンしている別のポートに内部的にリダイレクトするトラフィックの種類(ssh、httpsなど)を分析する、あるポートでリッスンするプログラムを使用することです。

たとえば、Linuxの場合、sslh: https://github.com/yrutschle/sslh

3
Mitchbcn

TCP接続を作成するときは、特定のTCPアドレスに接続するように要求します。これは、使用しているプロトコルに応じて、IPアドレス(v4またはv6)の組み合わせです。 )とポート。

サーバが接続を待ち受けるとき、それは特定のIPアドレスとポート、すなわち1つのTCPアドレス、または各ホストのIPアドレス上の同じポート上で待ち受けたいことをカーネルに知らせることができます。 (通常はIPアドレス0.0.0.0で指定されます)、事実上多くの異なる "TCPアドレス"(例えば192.168.1.10:8000127.0.0.1:8000など)をリッスンしています。

いいえ、2つのアプリケーションが同じ「TCPアドレス」をリッスンすることはできません。メッセージが入ってくると、カーネルはどのアプリケーションにメッセージを渡すべきかをどのように認識するのでしょうか。

ただし、ほとんどのオペレーティングシステムでは、1つのインタフェースに複数のIPアドレスを設定できます(たとえば、インタフェースに192.168.1.10がある場合、ネットワーク上に他の人が使用していなければ192.168.1.11も設定できます)場合によっては、これら2つのIPアドレスのそれぞれで別々のアプリケーションがポート8000をリ​​ッスンしている可能性があります。

2
Curt J. Sampson

少なくとも1つのリモートIPがすでに静的で、1つのアプリとのみ通信することがわかっている場合は、iptablesルール(table nat、chain PREROUTING)を使用して、このアドレスからの着信トラフィックを「共有」ローカルポートにリダイレクトします。適切なアプリケーションが実際に待機する他のポート。

2
Stemar

はい。

この記事から:
https://lwn.net/Articles/542629/

新しいソケットオプションにより、同じホスト上の複数のソケットが同じポートにバインドできるようになりました

1
user6169806

はいといいえ。 1つのアプリケーションだけがポートをアクティブに待機できます。しかし、そのアプリケーションは他のプロセスへの接続を遅らせることができます。したがって、同じポート上で複数のプロセスが動作している可能性があります。

1
rajesh

2つのアプリケーションが同じネットワークインターフェース上の同じポートをlistenするようにすることができます。

指定されたネットワークインタフェースとポートに対して待機するソケットは1つだけですが、そのソケットは複数のアプリケーション間で共有できます。

アプリケーションプロセス内に待機ソケットがあり、そのプロセスをforkと継承した場合、技術的には2つのプロセスが同じポートを待機するようになります。

0
warvariuc

私はsocatで次のことを試しました:

socat TCP-L:8080,fork,reuseaddr -

また、ソケットに接続していなくても、reuseaddrオプションにもかかわらず、同じポートで2回リスンすることはできません。

このメッセージが表示されます(以前に予想されていました)。

2016/02/23 09:56:49 socat[2667] E bind(5, {AF=2 0.0.0.0:8080}, 16): Address already in use
0
aDoN

@jnewtonが言ったことを共有するだけです。 Macでnginxと組み込みTomcatプロセスを開始しました。 8080で実行中の両方のプロセスを見ることができます。

LT<XXXX>-MAC:~ b0<XXX>$ Sudo netstat -anp tcp | grep LISTEN
tcp46      0      0  *.8080                 *.*                    LISTEN     
tcp4       0      0  *.8080                 *.*                    LISTEN   
0
Amit Parashar

アプリケーションによってあなたが複数のプロセスを意味するならば、はい、しかし一般にいいえ。たとえば、Apacheサーバーは同じポート(通常80)で複数のプロセスを実行します。実際にポートにバインドするプロセスの1つを指定し、そのプロセスを使用して接続を受け付けているさまざまなプロセスにハンドオーバーします。

0
nitinsh99