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


283

同じマシン上の2つのアプリケーションを同じポートとIPアドレスにバインドできますか?さらに一歩進んで、あるアプリが特定のIPからのリクエストをリッスンし、別のアプリが別のリモートIPへのリクエストをリッスンできますか?1つのアプリケーションで2つのスレッド(またはフォーク)から開始して同様の動作をさせることはできますが、共通点のない2つのアプリケーションでも同じことができますか?


2
複数のソケットでのアドレス/ポートの再利用に関する詳細な回答については、stackoverflow.com
questions

回答:


248

考えられるOSによって答えは異なります。一般的にはしかし:

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

UDP(マルチキャスト)の場合、複数のアプリケーションが同じポートにサブスクライブできます。

編集:Linuxカーネル3.9以降では、同じポートをリッスンする複数のアプリケーションのサポートがSO_REUSEPORTオプションを使用して追加されました。詳細については、このlwn.netの記事を参照してください。


22
「単一のポートでリッスンする1つのアプリケーション」が、ポートが存在する理由です。複数のアプリケーションが競合することなくネットワークを共有できるようにするためです。
S.Lott、2009年

46
IPアドレスごとにポートごとに1つのリスナー。別のネットワークインターフェイスを追加すると、2番目のIPアドレスを取得できます。プラットフォームはおそらく仮想インターフェイスをサポートしていますが、これは1つの物理ネットワークカードで2つのIPアドレスを取得するもう1つの方法です。
John M

7
今まで同じ意見でしたが、2つの異なるプロセスを同じIPおよびTCPポートにバインドできました。バインドする前にJavaでServerSocket.setReuseAddress(true)を設定すると、これが可能になります。本当に予想外の振る舞い。
Eugen

7
(1)回答の実際の意味は「TCPの場合、はい、提供されます...」です(2)マルチキャストはUDPポート共有の前提条件ではありませんが、SO_REUSEADDRはそうです。
ローン侯爵2013

12
UDP(マルチキャスト)の場合、複数のアプリケーションが同じポートにサブスクライブできます。クライアントから1つのパケットが到着した場合、どのアプリケーションがそれを受信しますか?
Yang Juven 2014

123

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

SO_REUSEADDR

bind()すでにポートにバインドされているアクティブなリスニングソケットがない限り、他のソケットがこのポートに接続できるようにします。これにより、クラッシュ後にサーバーを再起動しようとしたときに、「使用中のアドレス」エラーメッセージを回避できます。


1
TCP + UDPが機能するようになりました(十分に新しいカーネルを想定)。回答に追加したリンクを参照してください。
dpb 2013

3
すべてのソケットがINADDR_ANYでない個別のIPアドレスにバインドされていない限り、または結果が未定義であるWindowsを使用していない限り、この答えは正しくありません。
ローン侯爵2013

1
同じポートの特定のアプリにデータがどのように送られるかを詳しく説明できますか?アプリがSO_REUSEADDRまたはSO_REUSEPORTを使用する場合に考慮すべきセキュリティ上の懸念はありますか?
trusktr 2013

@EJP私の以前のコメントも見てください。
trusktr 2013

3
SO_REUSEADDR確かに、少なくともUnixでは、同時に2つのTCPソケットをリスニング状態にすることはできません。これは、unixguide.netTIME_WAIT state / network / socketfaq / 4.5.shtmlを回避するためのものです。Windowsでも機能する可能性がありますが、リクエストが正しいサーバーに到達することは保証されません)。
Bruno

48

はい。

  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。


手元にリンクがありますか?TCP-UDPの共存の機会が私の質問です。前もって感謝します:)
Wolf

1
@ウルフ試してみてください。それはあなたが本当に必要とするすべての証拠です。私の引用はStevens&Wrightです。あなたはそれ以上に良くなることはできません。
ローン侯爵2014年

1
回答ありがとうございます。もっと注意深く読む必要があります。UDPとTCP は共存できると既に書いています。
ウルフ

47

原則として、違います。

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

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

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

  1. Jedが述べたように、クライアント要求を分離したいロジックを使用して、ポートを実際にリッスンして他のユーザーに通知する唯一のプロセスである「マスター」プロセスを作成できます。
    • LinuxおよびBSD(少なくとも)では、ネットワーク関連の基準(たぶん起点のネットワークまたは単純な形式のロードバランシング)。

37
iptables -m statistic --mode random --probability 0.5楽しいです。
ジェッド・スミス

1
「ポートを開く」とはどういう意味ですか?文章は理解しましたが、システムがポートを開いて処理したときのシステムの動作を正確に知っていますか?TCPでポートを開きたい場合、ストリームを取得し、そのストリームがリモートとの接続であることを知っていますが、私はWebで検索して、非常に良い説明が見つかりませんでした。
Samuel

4
@Samuel:(サーバーモードで)ポートを開くことは、ファイル記述子を取得することを意味し、システムがそのポート番号へのSYNパケットを取得すると、SYN + ACKで応答し、関連するファイル記述子でイベントを生成します。アプリケーションは、特定のストリームに関連付けられた新しいファイル記述子を作成するaccept()呼び出しでそのイベントに応答し、元のサーバー記述子を解放して、クライアントから新しい接続を取得できるようにします
Javier

7
この答えは正しいとは言えません。SO_REUSEADDRとSO_REUSEPORTの両方の存在を完全に無視しています。
ローンの侯爵2012

@Javierいいえ、ありません。サーバーアプリケーションの観点からポートを開くのは、リスニングソケットをバインドするとき、または接続しようとしているソケットをバインドするときですlisten()。おそらく問題はファイアウォールでそれを開くことです。ここでは非常に多くのエラーがあり、7年間はすべて修正されていません。Answerは、同じポート番号を持つ異なるローカルアドレスにバインドする場合も省略します。それは実際には完全に間違っています。
ローン侯爵

27

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

TCPUDPの両方で機能します。詳細については、リンクを参照してください:SO_REUSEPORT

:私の意見では、受け入れられた回答はもはや真実ではありません。


2
ほんと。それが真実ではなかった場合、Wiresharkはどのように機能しますか?
Staszek 2017年

5
@Staszek Wiresharkはポートをリッスンしません。パケットレベルで動作します。
ローン侯爵

ああ、それは理にかなっています。とにかく、2つのアプリで2つのポートをリッスンすることは確かに可能です。
Staszek

18

いいえ。一度にポートにバインドできるアプリケーションは1つだけであり、バインドが強制された場合の動作は不確定です。

マルチキャストソケット(希望するものに近いとは思えない)の場合、各ソケットのオプションでSO_REUSEADDRが設定されている限り、複数のアプリケーションがポートにバインドできます。

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

これ以外にも、詳細について調べています-TCPとUDPの両方にタグを付けましたが、それは何ですか?また、どのプラットフォームですか?


どちらも私にとって興味深いものです。プラットフォームはWindowsですが、Linuxの答えが異なる場合は、知っておくとよいでしょう
nadiv

8
マルチキャストソケットのようなものはありません。UDPソケットがあります。マルチキャストはSO_REUSEADDRの前提条件ではありません。
ローンの侯爵2013

3

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

  1. httpd リモートでアクセス可能なインターフェース、例えば 192.168.1.1:80
  2. 待機している別のデーモン 127.0.0.1:80

サンプルユースケースはhttpd、ロードバランサーまたはプロキシとして使用することです。


3

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

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


Windowsにそのようなプログラムはありますか?ローカルIISサーバーとActiveMQブローカーの両方をポート443でリッスンする必要があります
Harvey Lin

3

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

サーバーが接続をリッスンするとき、特定の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場合、ネットワーク上の他のユーザーがそれを使用していない場合は、を設定することもできます)。8000これら2つのIPアドレスのそれぞれのポートでリッスンする個別のアプリケーションを使用できます。


2

リモートIPの少なくとも1つが既知であり、静的で、アプリの1つとのみ通信するようになっている場合は、iptablesルール(テーブルNAT、チェーンPREROUTING)を使用して、このアドレスからの受信トラフィックを「共有」ローカルポートにリダイレクトできます。適切なアプリケーションが実際にリッスンする他のポート。


1

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


@trusktr、私は彼がこれ
warvariuc '12 / 08/12

1

はい。

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

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


1
素敵なリンクですが、ここにこの行を記述しないでください-SO_REUSEPORTオプションは非標準です
Sahil Singh

0

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


0

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

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

アプリケーションプロセスにリスニングソケットがあり、forkそのプロセスを使用している場合、ソケットは継承されるため、技術的には2つのプロセスが同じポートをリスニングするようになります。


0

私は以下を試しました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

@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   

-2

短い答え:

ここで与えられた答えで行く。同じIPアドレスとポート番号で2つのアプリケーションをリッスンすることができます。そのため、ポートの一方がUDPポートであり、もう一方がTCPポートです。

説明:

ポートの概念はTCP / IPスタックのトランスポート層に関連するため、スタックの異なるトランスポート層プロトコルを使用している限り、同じ<ip-address>:<port>組み合わせで複数のプロセスがリッスンすることができます。

2つのアプリケーションが同じ<ip-address>:<port>組み合わせで実行されている場合、リモートマシンで実行されているクライアントは2つをどのように区別するのでしょうか。IPレイヤーパケットヘッダー(https://en.wikipedia.org/wiki/IPv4#Header)を見ると、プロトコルの定義にビット72〜79が使用されていることがわかります。これにより、区別を行うことができます。

ただし、同じTCPの<ip-address>:<port>組み合わせで2つのアプリケーションを使用したい場合、答えは「いいえ」です(興味深い演習では、2つのVMを起動し、それらに同じIPアドレスを与えますが、異なるMACアドレスを与え、何が起こるかを確認します-時々気づくでしょうVM1はパケットを取得し、それ以外の場合はVM2がパケットを取得します(ARPキャッシュの更新によって異なります)。

2つのアプリケーションを同じ上で実行<op-address>:<port>することで、ある種のロードバランシングを実現したいと思います。このため、異なるポートでアプリケーションを実行し、IPテーブルルールを記述して、ポート間のトラフィックを分岐させることができます。

@ user6169806の回答もご覧ください。

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