两个应用程序可以侦听同一端口吗?


283

同一台计算机上的两个应用程序可以绑定到相同的端口和IP地址吗?更进一步,一个应用程序可以监听来自某个IP的请求,另一个监听来自另一个IP的请求吗?我知道我可以有一个从两个线程(或分支)开始的应用程序,它们具有相似的行为,但是两个没有共同点的应用程序可以做到相同吗?


2
有关重用地址/端口,多插槽的好详细的解答:stackoverflow.com/questions/14388706/...
Bjarke弗氏-汉森

Answers:


248

答案因所考虑的操作系统而异。一般而言:

对于TCP,否。一次只能有一个应用程序在同一端口上侦听。现在,如果您有2个网卡,则可以让一个应用程序使用相同的端口号监听第一个IP,第二个监听第二个IP。

对于UDP(多播),多个应用程序可以订阅同一端口。

编辑:自Linux Kernel 3.9及更高版本起,使用该SO_REUSEPORT选项添加了对侦听同一端口的多个应用程序的支持。有关更多信息,请参见lwn.net。


22
“一个应用程序在单个端口上侦听”是端口存在的原因-允许多个应用程序共享网络而不会发生冲突。
S.Lott

46
每个IP地址每个端口一个侦听器。添加另一个网络接口是获取第二个IP地址的一种方法。您的平台可能支持虚拟接口,这是通过一个物理网卡获取两个IP地址的另一种方法。
约翰M,2009年

7
尽管直到现在我还是持相同观点,但事实证明,我能够将两个不同的进程绑定到相同的ip和TCP端口!如果在绑定到Java之前在Java中设置ServerSocket.setReuseAddress(true),则可以这样做。确实出乎意料的行为。
欧根(Eugen)

7
(1)答案的实际含义是“对于TCP,是,提供...”(2)组播不是UDP端口共享的前提,但SO_REUSEADDR是。
罗恩侯爵,

12
对于UDP(多播),多个应用程序可以订阅同一端口。如果一个数据包从客户端到达,哪个应用程序收到它?
杨·尤文2014年

123

是的(对于TCP),如果程序被设计为可以在同一个套接字上侦听两个程序。由第一个程序创建套接字时,请先确保SO_REUSEADDR已在套接字上设置了该选项bind()。但是,这可能不是您想要的。这样做是将传入TCP连接定向到其中一个程序,而不是两者都定向,因此它不会重复连接,它只允许两个程序为传入请求提供服务。例如,Web服务器将有多个进程都在端口80上侦听,并且O / S将新连接发送到准备接受新连接的进程。

SO_REUSEADDR

允许其他套接字连接bind()到该端口,除非已经有活动的侦听套接字绑定到该端口。当您在崩溃后尝试重新启动服务器时,这使您能够解决那些“地址已在使用中”的错误消息。


1
TCP + UDP现在可以工作了(有了足够新的内核)。请参阅我添加到答案的链接。
2013年

3
除非所有套接字都绑定到都不是INADDR_ANY的不同IP地址,或者除非您使用的Windows未定义结果,否则此答案是不正确的。
罗恩侯爵

1
您是否可以扩展数据如何通过同一端口到达特定应用程序?应用程序使用SO_REUSEADDR或SO_REUSEPORT时是否需要考虑任何安全方面的考虑?
trusktr

@EJP您还能看看我以前的评论吗?
trusktr

3
SO_REUSEADDR当然,至少在Unix上,肯定不允许两个TCP套接字同时处于侦听状态。它旨在解决TIME_WAIT stateunixguide.net/network/socketfaq/4.5.shtml。它可能在Windows上可以运行,但不能保证无论如何该请求都会到达正确的服务器。
布鲁诺

48

是。

  1. 如果它们都绑定到不同的本地IP地址,则可以将多个侦听TCP套接字(都绑定到同一端口)共存。客户端可以连接到所需的任何一个。这不包括0.0.0.0INADDR_ANY)。

  2. 多个接受的套接字可以共存,所有套接字都从同一个侦听套接字接受,并且都显示与侦听套接字相同的本地端口号。

  3. 提供与(1)相同的条件,可以将全部绑定到同一端口的多个UDP套接字共存,或者SO_REUSEADDR在绑定之前都设置了选项。

  4. TCP端口和UDP端口占用不同的名称空间,因此将端口用于TCP并不排除将其用于UDP,反之亦然。

参考:Stevens&Wright,TCP / IP图解,第二卷。


您手边有链接吗?TCP-UDP共存的机会是我的问题。在此先感谢:)

1
@狼只要尝试一下。这就是您真正需要的证明。我的引文是史蒂文斯与赖特(Stevens&Wright):您再也无法比这更好。
洛恩侯爵,

1
感谢您的答复,我需要更仔细地阅读。您已经写过UDP和TCP 可以共存

47

原则上不可以。

它不是一成不变的。但这是编写所有API的方式:该应用程序打开一个端口,获取该端口的句柄,然后当客户端连接(或UDP情况下的数据包)到达时,操作系统(通过该句柄)通知该端口。

如果操作系统允许两个应用程序打开相同的端口,它将如何知道要通知哪个应用程序?

但是...有一些解决方法:

  1. 如Jed 所述,您可以编写一个“主”进程,该进程将使用它想要分离客户端请求的任何逻辑来真正监听端口并通知其他人。
    • 在Linux和BSD上(至少),您可以设置“重新映射”规则,根据任何与网络相关的标准(可能是源网络或某些网络)将数据包从“可见”端口重定向到其他端口(应用正在监听)。负载平衡的简单形式)。

37
iptables -m statistic --mode random --probability 0.5有趣。
杰德·史密斯

1
到底什么意思表示“打开端口”?我明白这句话,但是您知道系统打开端口并处理该端口时系统将执行什么操作吗?我知道,当您想使用TCP打开端口时,会得到一个流,并且该流是您与远程服务器的连接,但是我在网络上搜索并没有找到很好的解释。
塞缪尔2010年

4
@Samuel:打开端口(在服务器模式下)意味着获取文件描述符,并且当系统获取到该端口号的SYN数据包时,以SYN + ACK响应并在关联的文件描述符上生成事件。应用程序通过accept()调用来响应该事件,该调用将创建一个与特定流相关联的新文件描述符,而原始服务器描述符则可以自由地从客户端获取新的连接
Javier 2010年

7
这个答案不能被认为是正确的。它完全忽略了SO_REUSEADDR和SO_REUSEPORT的存在。
洛恩侯爵,2012年

@哈维尔不,不是。从服务器应用程序的角度来看,打开端口是在您绑定监听套接字或绑定您将要listen()打开的套接字时发生的。问题很可能是关于在防火墙中打开它。这里的错误太多,而且7年内都未纠正。答案还省略了绑定到具有相同端口号的不同本地地址的情况。实际上这是完全不正确的。
罗恩侯爵,

27

是的。据我记得,从3.9版内核(不确定该版本)开始,SO_REUSEPORT就引入了对它的支持。SO_RESUEPORT允许绑定到完全相同的端口和地址,只要第一台服务器在绑定其套接字之前设置此选项。

它适用于TCPUDP。请参阅链接以获取更多详细信息:SO_REUSEPORT

注意:根据我的观点,接受的答案不再成立。


2
完全正确。如果事实并非如此,那么Wireshark如何工作?
Staszek '17

5
@Staszek Wireshark不监听端口。它在数据包级别运行。
罗恩侯爵

哦,那很有道理。无论如何,通过2个应用监听两个端口肯定是可能的。
Staszek

18

否。一次只能将一个应用程序绑定到端口,如果强制执行绑定,则行为是不确定的。

使用多播套接字-听起来像没有想要的东西-只要在每个套接字的选项中设置了SO_REUSEADDR,就可以将多个应用程序绑定到一个端口。

您可以通过编写一个“主”进程来完成此任务,该进程接受并处理所有连接,然后将它们交给需要在同一端口上侦听的两个应用程序。这是Web服务器之类的方法,因为许多进程需要监听80。

除此之外,我们还将介绍一些细节-您标记了TCP和UDP,是吗?还有,什么平台?


两者都令我感兴趣。该平台是Windows,但是如果Linux的答案不同,那就很高兴了
nadiv

8
没有诸如多播套接字之类的东西。有UDP套接字。组播不是SO_REUSEADDR的前提。
洛恩侯爵,

3

您可以让一个应用程序在一个端口上侦听一个网络接口。因此,您可以:

  1. httpd 在远程访问界面上侦听,例如 192.168.1.1:80
  2. 另一个守护进程在监听 127.0.0.1:80

示例用例可以httpd用作负载平衡器或代理。


3

另一种方法是使用一个程序在一个端口中侦听,该程序分析其内部重定向到“真实”服务正在侦听的另一个端口的流量(ssh,https等)。

例如,对于Linux,sslh:https : //github.com/yrutschle/sslh


Windows上有这样的程序吗?我需要我的两个本地IIS服务器和ActiveMQ代理在端口443听
哈维林

3

创建TCP连接时,您要求连接到特定的TCP地址,该地址是IP地址(v4或v6,取决于所使用的协议)和端口的组合。

当服务器侦听连接时,它可以通知内核它想侦听特定的IP地址和端口,即一个TCP地址,或者侦听主机IP地址中每个主机的同一端口(通常用IP地址指定)0.0.0.0),其上有很多不同的“TCP地址”的有效监听(例如,192.168.1.10:8000127.0.0.1:8000等等)

不,您不能让两个应用程序侦听相同的“ TCP地址”,因为当消息进入时,内核如何知道向哪个应用程序发送消息?

但是,在大多数操作系统中,您可以在一个接口上设置多个IP地址(例如,如果192.168.1.10在接口上,则还可以设置192.168.1.11,如果网络上没有其他人正在使用它),在这种情况下,您可以可能有单独的应用程序在8000这两个IP地址的每个端口上侦听端口。


2

如果至少有一个远程IP是已知的,静态的并且专用于仅与您的一个应用程序对话,则可以使用iptables规则(table nat,链PREROUTING)将传入流量从该地址重定向到“共享”本地端口,适当的应用程序实际侦听的任何其他端口。


1

是的,没有。只有一个应用程序可以主动侦听端口。但是该应用程序可以保留其与另一个进程的连接。因此,您可以在同一端口上运行多个进程。


@trusktr,我想他的意思是
warvariuc


0

如果按应用程序表示多个进程,则可以,但通常不可以。例如,Apache服务器在同一个端口(通常为80)上运行多个进程,这是通过指定其中一个进程实际绑定到该端口,然后使用该进程将切换到接受连接的各个进程来完成的。


0

您可以使两个应用程序侦听同一网络接口上的同一端口。

指定的网络接口和端口只能有一个侦听套接字,但是该套接字可以在多个应用程序之间共享。

如果在应用程序进程中有一个侦听套接字,并且fork该进程将被继承,那么从技术上讲,现在将有两个进程在侦听同一端口。


0

我已经尝试了以下方法socat

socat TCP-L:8080,fork,reuseaddr -

即使我没有与套接字建立连接,尽管有reuseaddr选择,我也无法在同一端口上侦听两次。

我收到此消息(之前我曾期望过):

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看到两个进程runninng。

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

-2

简短答案:

按照这里给出的答案。您可以让两个应用程序侦听相同的IP地址和端口号,因此一个端口只要是UDP端口,而另一个是TCP端口即可。

说明:

端口的概念与TCP / IP堆栈的传输层相关,因此,只要您使用堆栈的不同传输层协议,就可以使多个进程侦听相同的<ip-address>:<port>组合。

人们存在的一个疑问是,如果两个应用程序在同一<ip-address>:<port>组合上运行,那么在远程计算机上运行的客户端如何区分两者?如果查看IP层数据包标头(https://en.wikipedia.org/wiki/IPv4#Header),将会看到第72到79位用于定义协议,这是可以区分的。

但是,如果您希望在同一TCP <ip-address>:<port>组合上具有两个应用程序,那么答案是否定的(一个有趣的练习是启动两个VM,为它们提供相同的IP地址,但提供不同的MAC地址,然后看看会发生什么-您会注意到有时VM1将获取数据包,而其他时间VM2将获取数据包-取决于ARP缓存刷新)。

我觉得通过使两个应用程序在相同的环境下运行,<op-address>:<port>您希望实现某种负载平衡。为此,您可以在不同的端口上运行应用程序,并编写IP表规则以分流它们之间的流量。

另请参阅@ user6169806的答案。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.