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


当前回答

Yes.

Multiple listening TCP sockets, all bound to the same port, can co-exist, provided they are all bound to different local IP addresses. Clients can connect to whichever one they need to. This excludes 0.0.0.0 (INADDR_ANY). Multiple accepted sockets can co-exist, all accepted from the same listening socket, all showing the same local port number as the listening socket. Multiple UDP sockets all bound to the same port can all co-exist provided either the same condition as at (1) or they have all had the SO_REUSEADDR option set before binding. TCP ports and UDP ports occupy different namespaces, so the use of a port for TCP does not preclude its use for UDP, and vice versa.

参考资料:Stevens & Wright, TCP/IP画报,卷二。

其他回答

在创建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上设置单独的应用程序。

原则上,没有。

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

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

但是…有一些方法可以解决这个问题:

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

如果至少有一个远程ip是已知的,静态的,专用于只与你的一个应用程序对话,你可以使用iptables规则(表nat,链PREROUTING)来重定向从这个地址到“共享”本地端口的传入流量到任何其他端口,其中适当的应用程序实际监听。

简短的回答:

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

解释:

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

人们有一个疑问,如果两个应用程序运行在相同的<ip-address>:<端口>组合上,那么在远程机器上运行的客户机如何区分这两个应用程序?如果你看一下IP层数据包头(https://en.wikipedia.org/wiki/IPv4#Header),你会发现第72位到第79位是用来定义协议的,这就是如何区分的。

然而,如果你想让两个应用程序在相同的TCP < IP -address>:<port>组合上,那么答案是否定的(一个有趣的练习是启动两个vm,给它们相同的IP地址,但不同的MAC地址,看看会发生什么——你会注意到有些时候VM1将获得数据包,而其他时候VM2将获得数据包——这取决于ARP缓存刷新)。

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

请参见@user6169806的回答。

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

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