同一台机器上的两个应用程序可以绑定到相同的端口和 IP 地址吗?更进一步,一个应用程序可以侦听来自某个 IP 的请求,而另一个应用程序可以侦听来自另一个远程 IP 的请求吗?我知道我可以让一个应用程序启动两个线程(或分叉)以具有相似的行为,但是两个没有共同点的应用程序可以做同样的事情吗?
答案因所考虑的操作系统而异。但总的来说:
对于 TCP,没有。您一次只能让一个应用程序在同一个端口上侦听。现在,如果您有 2 个网卡,则可以让一个应用程序使用相同的端口号侦听第一个 IP 和第二个 IP 上的第二个应用程序。
对于 UDP(多播),多个应用程序可以订阅同一个端口。
编辑:从 Linux Kernel 3.9 及更高版本开始,使用 SO_REUSEPORT
选项添加了对侦听同一端口的多个应用程序的支持。如需更多信息,请访问 this lwn.net article.
是的(对于 TCP)你可以让两个程序在同一个套接字上侦听,如果程序被设计为这样做的话。当第一个程序创建套接字时,请确保在 bind()
之前在套接字上设置了 SO_REUSEADDR
选项。但是,这可能不是您想要的。这样做的目的是将传入的 TCP 连接定向到 一个 程序,而不是两个程序,因此它不会复制连接,它只允许两个程序为传入请求提供服务。例如,Web 服务器将有多个进程都在侦听端口 80,并且 O/S 向准备接受新连接的进程发送一个新连接。
SO_REUSEADDR
允许其他套接字 bind()
到此端口,除非已经有一个活动的侦听套接字绑定到该端口。这使您能够在崩溃后尝试重新启动服务器时绕过那些“地址已在使用中”的错误消息。
SO_REUSEADDR
肯定不会让您同时拥有两个处于侦听状态的 TCP 套接字,至少在 Unix 上是这样。它旨在绕过 TIME_WAIT state
: unixguide.net/network/socketfaq/4.5.shtml 。它可能在 Windows 上工作,但你不能保证请求会到达正确的服务器)。
是的。
绑定到同一个端口的多个侦听 TCP 套接字可以共存,前提是它们都绑定到不同的本地 IP 地址。客户可以连接到他们需要的任何一个。这不包括 0.0.0.0 (INADDR_ANY)。多个接受的套接字可以共存,都从同一个侦听套接字接受,都显示与侦听套接字相同的本地端口号。绑定到同一端口的多个 UDP 套接字都可以共存,前提是与 (1) 中的条件相同,或者它们在绑定之前都设置了 SO_REUSEADDR 选项。 TCP 端口和 UDP 端口占用不同的命名空间,因此将端口用于 TCP 并不排除其用于 UDP,反之亦然。
参考:Stevens & Wright,TCP/IP 图解,第二卷。
原则上,没有。
它不是一成不变的;但这是所有 API 的编写方式:应用程序打开一个端口,获取它的句柄,当客户端连接(或 UDP 情况下的数据包)到达时,操作系统(通过该句柄)通知它。
如果操作系统允许两个应用程序打开同一个端口,它怎么知道通知哪一个?
但是......有一些方法可以解决它:
正如 Jed 所指出的,您可以编写一个“主”进程,这将是唯一真正监听端口并通知其他人的进程,使用它想要分离客户端请求的任何逻辑。在 Linux 和 BSD(至少)上,您可以设置“重新映射”规则,根据任何与网络相关的标准(可能是源网络或某些负载平衡的简单形式)。
iptables -m statistic --mode random --probability 0.5
很有趣。
listen()
的套接字。更可能的问题是在防火墙中打开它。这里的错误太多了,而且在 7 年内都没有得到纠正。 Answer 也省略了绑定到具有相同端口号的不同本地地址的情况。事实上,这是完全不正确的。
肯定是的。据我所知,从内核版本 3.9(不确定版本)开始,引入了对 SO_REUSEPORT
的支持。 SO_RESUEPORT
允许绑定到完全相同的端口和地址,只要第一个服务器在绑定其套接字之前设置此选项。
它适用于 TCP 和 UDP。有关详细信息,请参阅链接:SO_REUSEPORT
注意:根据我的观点,接受的答案不再适用。
不可以。一次只有一个应用程序可以绑定到一个端口,如果强制绑定,行为是不确定的。
使用多播套接字——这听起来离你想要的很远——只要在每个套接字的选项中设置了 SO_REUSEADDR,就可以将多个应用程序绑定到一个端口。
您可以通过编写一个“主”进程来完成此操作,该进程接受并处理所有连接,然后将它们交给需要在同一端口上侦听的两个应用程序。这是 Web 服务器等采用的方法,因为许多进程需要监听 80。
除此之外,我们正在进入细节——你标记了 TCP 和 UDP,是什么?还有,什么平台?
您可以让一个应用程序在一个端口上侦听一个网络接口。因此,您可以:
httpd 监听远程访问接口,例如 192.168.1.1:80 另一个守护进程监听 127.0.0.1:80
示例用例可能是将 httpd
用作负载平衡器或代理。
创建 TCP 连接时,您要求连接到特定的 TCP 地址,该地址是 IP 地址(v4 或 v6,取决于您使用的协议)和端口的组合。
当服务器监听连接时,它可以通知内核它想监听一个特定的 IP 地址和端口,即一个 TCP 地址,或者在每个主机的 IP 地址上的同一端口上(通常用 IP 地址指定) 0.0.0.0
),它有效地侦听许多不同的“TCP 地址”(例如,192.168.1.10:8000
、127.0.0.1:8000
等)
不,你不能让两个应用程序监听同一个“TCP 地址”,因为当消息进入时,内核如何知道将消息提供给哪个应用程序?
但是,在大多数操作系统中,您可以在单个接口上设置多个 IP 地址(例如,如果您在接口上有 192.168.1.10
,您也可以设置 192.168.1.11
,如果网络上没有其他人在使用它) ,在这些情况下,您可以让单独的应用程序在这两个 IP 地址中的每一个上的端口 8000
上进行侦听。
只是为了分享@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
另一种方法是使用在一个端口中侦听的程序来分析它在内部重定向到“真实”服务正在侦听的另一个端口的流量类型(ssh、https 等)。
例如,对于 Linux,sslh:https://github.com/yrutschle/sslh
如果至少有一个远程 IP 是已知的、静态的并且专用于仅与您的一个应用程序通信,您可以使用 iptables 规则(表 nat,链 PREROUTING)将来自该地址的传入流量重定向到“共享”本地端口到适当的应用程序实际侦听的任何其他端口。
是的。
来自这篇文章:
https://lwn.net/Articles/542629/
新的套接字选项允许同一主机上的多个套接字绑定到同一端口
如果应用程序是指多个进程,那么是的,但通常不是。例如,Apache 服务器在同一个端口(通常为 80)上运行多个进程。这是通过指定一个进程实际绑定到该端口,然后使用该进程切换到接受连接的各种进程来完成的。
您可以让两个应用程序在同一个网络接口上侦听同一个端口。
指定的网络接口和端口只能有一个侦听套接字,但该套接字可以在多个应用程序之间共享。
如果您在应用程序进程中有一个侦听套接字并且您fork
该进程,则该套接字将被继承,因此从技术上讲,现在将有两个进程侦听同一个端口。
我用 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
简短的回答:
按照给出的答案 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 的答案。