同一台机器上的两个应用程序可以绑定到相同的端口和 IP 地址吗?更进一步,一个应用程序可以侦听来自某个 IP 的请求,而另一个应用程序可以侦听来自另一个远程 IP 的请求吗?我知道我可以让一个应用程序启动两个线程(或分叉)以具有相似的行为,但是两个没有共同点的应用程序可以做同样的事情吗?
17 回答
答案因所考虑的操作系统而异。但总的来说:
对于 TCP,没有。您一次只能让一个应用程序在同一个端口上侦听。现在,如果您有 2 个网卡,则可以让一个应用程序使用相同的端口号侦听第一个 IP 和第二个 IP 上的第二个应用程序。
对于 UDP(多播),多个应用程序可以订阅同一个端口。
SO_REUSEPORT
编辑:自 Linux Kernel 3.9 及更高版本以来,使用该选项添加了对侦听同一端口的多个应用程序的支持。此 lwn.net 文章中提供了更多信息。
是的(对于 TCP)你可以让两个程序在同一个套接字上侦听,如果程序被设计为这样做的话。当第一个程序创建套接字时,请确保SO_REUSEADDR
在您之前在套接字上设置了该选项bind()
。但是,这可能不是您想要的。这样做是一个传入的 TCP 连接将被定向到其中一个程序,而不是两个程序,因此它不会复制连接,它只允许两个程序为传入的请求提供服务。例如,Web 服务器将有多个进程都在侦听端口 80,并且 O/S 向准备接受新连接的进程发送一个新连接。
SO_REUSEADDR
允许其他套接字连接bind()
到该端口,除非已经有一个活动的侦听套接字绑定到该端口。这使您能够在崩溃后尝试重新启动服务器时绕过那些“地址已在使用中”的错误消息。
是的。
绑定到同一个端口的多个侦听 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(至少)上,您可以设置“重新映射”规则,根据任何与网络相关的标准(可能是源网络或某些负载平衡的简单形式)。
是的 绝对。据我记得从内核版本 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
,如果网络上没有其他人在使用它),在这些情况下,您可以有单独的应用程序监听8000
这两个 IP 地址中的每一个的端口。
另一种方法是使用在一个端口中侦听的程序来分析它在内部重定向到“真实”服务正在侦听的另一个端口的流量类型(ssh、https 等)。
例如,对于 Linux,sslh:https ://github.com/yrutschle/sslh
只是为了分享@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
如果至少有一个远程 IP 是已知的、静态的并且专用于仅与您的一个应用程序通信,您可以使用 iptables 规则(表 nat,链 PREROUTING)将来自该地址的传入流量重定向到“共享”本地端口到适当的应用程序实际侦听的任何其他端口。
是和不是。只有一个应用程序可以主动监听一个端口。但是该应用程序可以将其连接到另一个进程。所以你可以有多个进程在同一个端口上工作。
如果应用程序是指多个进程,那么是的,但通常不是。例如,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
简短的回答:
按照这里给出的答案。您可以让两个应用程序监听相同的 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 的答案。