ChatGPT解决这个技术问题 Extra ChatGPT

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

同一台机器上的两个应用程序可以绑定到相同的端口和 IP 地址吗?更进一步,一个应用程序可以侦听来自某个 IP 的请求,而另一个应用程序可以侦听来自另一个远程 IP 的请求吗?我知道我可以让一个应用程序启动两个线程(或分叉)以具有相似的行为,但是两个没有共同点的应用程序可以做同样的事情吗?

有关重用具有多个套接字的地址/端口的详细答案:stackoverflow.com/questions/14388706/…

C
Chris Dail

答案因所考虑的操作系统而异。但总的来说:

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

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

编辑:从 Linux Kernel 3.9 及更高版本开始,使用 SO_REUSEPORT 选项添加了对侦听同一端口的多个应用程序的支持。如需更多信息,请访问 this lwn.net article.


“一个应用程序侦听单个端口”这就是端口存在的原因 - 允许多个应用程序共享网络而不会发生冲突。
每个 IP 地址每个端口一个侦听器。添加另一个网络接口是获取第二个 IP 地址的一种方法。您的平台可能支持虚拟接口,这是使用一个物理网卡获取两个 IP 地址的另一种方法。
虽然直到现在我的意见相同,但事实证明我能够将两个不同的进程绑定到相同的 ip 和 TCP 端口!如果在绑定之前在 Java 中设置 ServerSocket.setReuseAddress(true) ,这是可能的。真是出乎意料的行为。
(1) 你的答案的实际意思是'对于 TCP,是的,提供......' (2) 多播不是 UDP 端口共享的先决条件,但 SO_REUSEADDR 是。
对于 UDP(多播),多个应用程序可以订阅同一个端口。如果一个数据包从客户端到达,哪个应用程序接收它?
U
Udo Held

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

SO_REUSEADDR

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


TCP + UDP 现在可以工作(给定一个足够新的内核)。请参阅我添加到答案的链接。
这个答案是不正确的,除非所有套接字都绑定到不同的 IP 地址,这些地址都不是 INADDR_ANY,或者除非你在 Windows 上,结果未定义。
您能否详细说明数据如何传输到同一端口上的特定应用程序?当应用程序使用 SO_REUSEADDR 或 SO_REUSEPORT 时,是否需要考虑任何安全问题?
@EJP 你能看看我之前的评论吗?
SO_REUSEADDR 肯定不会让您同时拥有两个处于侦听状态的 TCP 套接字,至少在 Unix 上是这样。它旨在绕过 TIME_WAIT state: unixguide.net/network/socketfaq/4.5.shtml 。它可能在 Windows 上工作,但你不能保证请求会到达正确的服务器)。
w
warvariuc

是的。

绑定到同一个端口的多个侦听 TCP 套接字可以共存,前提是它们都绑定到不同的本地 IP 地址。客户可以连接到他们需要的任何一个。这不包括 0.0.0.0 (INADDR_ANY)。多个接受的套接字可以共存,都从同一个侦听套接字接受,都显示与侦听套接字相同的本地端口号。绑定到同一端口的多个 UDP 套接字都可以共存,前提是与 (1) 中的条件相同,或者它们在绑定之前都设置了 SO_REUSEADDR 选项。 TCP 端口和 UDP 端口占用不同的命名空间,因此将端口用于 TCP 并不排除其用于 UDP,反之亦然。

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


你手头有链接吗? TCP-UDP共存的机会是我的问题。提前致谢:)
@Wolf 试试吧。这就是你真正需要的所有证据。我的引文是 Stevens & Wright:没有比这更好的了。
感谢您的回复,我需要更仔细地阅读。您已经写过 UDP 和 TCP 可以共存。
C
Community

原则上,没有。

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

如果操作系统允许两个应用程序打开同一个端口,它怎么知道通知哪一个?

但是......有一些方法可以解决它:

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


iptables -m statistic --mode random --probability 0.5 很有趣。
“打开一个端口”到底是什么意思?我理解这句话,但你知道系统打开一个端口并处理它时究竟做了什么吗?我知道当你想用 TCP 打开一个端口时,你会得到一个流,这个流是你与远程的连接,但我在网上搜索并没有找到很好的解释。
@Samuel:打开一个端口(在服务器模式下)意味着获取一个文件描述符,当系统收到一个到该端口号的 SYN 数据包时,以 SYN+ACK 响应并在关联的文件描述符上生成一个事件。应用程序通过 accept() 调用响应该事件,该调用创建一个与特定流关联的新文件描述符,使原始服务器描述符可以自由地从客户端获取新连接
这个答案不能被认为是正确的。它完全忽略了 SO_REUSEADDR 和 SO_REUSEPORT 的存在。
@Javier 不,不是。从服务器应用程序的角度打开端口发生在您绑定侦听套接字时,或者更确切地说是绑定您将要使用 listen() 的套接字。更可能的问题是在防火墙中打开它。这里的错误太多了,而且在 7 年内都没有得到纠正。 Answer 也省略了绑定到具有相同端口号的不同本地地址的情况。事实上,这是完全不正确的。
p
piyush

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

它适用于 TCPUDP。有关详细信息,请参阅链接:SO_REUSEPORT

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


完全正确。如果不是真的,那么 Wireshark 是如何工作的?
@Staszek Wireshark 不监听端口。它在数据包级别运行。
哦,那是有道理的。无论如何,肯定可以通过 2 个应用程序监听两个端口。
谢谢,如果不是这个答案,我永远不会知道为什么我正在使用的 http 服务器库允许绑定相同的端口。
J
Jed Smith

不可以。一次只有一个应用程序可以绑定到一个端口,如果强制绑定,行为是不确定的。

使用多播套接字——这听起来离你想要的很远——只要在每个套接字的选项中设置了 SO_REUSEADDR,就可以将多个应用程序绑定到一个端口。

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

除此之外,我们正在进入细节——你标记了 TCP 和 UDP,是什么?还有,什么平台?


两者都对我感兴趣。平台是 windows,但如果 Linux 的答案不同,很高兴知道
没有多播套接字这样的东西。有UDP套接字。多播不是 SO_REUSEADDR 的先决条件。
T
Tomas Tomecek

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

httpd 监听远程访问接口,例如 192.168.1.1:80 另一个守护进程监听 127.0.0.1:80

示例用例可能是将 httpd 用作负载平衡器或代理。


c
cjs

创建 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,如果网络上没有其他人在使用它) ,在这些情况下,您可以让单独的应用程序在这两个 IP 地址中的每一个上的端口 8000 上进行侦听。


A
Amit Parashar

只是为了分享@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   

C
Community

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

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


windows上有这样的程序吗?我需要让我的本地 IIS 服务器和 ActiveMQ 代理在端口 443 上侦听
S
Stemar

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


P
Pang

是的。

来自这篇文章:
https://lwn.net/Articles/542629/

新的套接字选项允许同一主机上的多个套接字绑定到同一端口


不错的链接,但是不要写在那里 - SO_REUSEPORT 选项是非标准的
r
rajesh

是和不是。只有一个应用程序可以主动监听一个端口。但是该应用程序可以将其连接到另一个进程。所以你可以有多个进程在同一个端口上工作。


@trusktr,我认为他的意思是this
j
java_doctor_101

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


w
warvariuc

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

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

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


a
aDoN

我用 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

C
Community

简短的回答:

按照给出的答案 here。您可以让两个应用程序监听相同的 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 的答案。


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅