那么端口根本不是机器所独有的吗?

那么端口根本不是机器所独有的吗?
$ lsof

memcached 15844 root   28u  IPv6     113604       TCP *:11051 (LISTEN)
memcached 15844 root   29u  IPv4     113605       TCP *:11051 (LISTEN)
memcached 15844 root   30u  IPv6     113609       UDP *:11051 
memcached 15844 root   31u  IPv4     113610       UDP *:11051 

是按 IP、按协议还是按其他维度?

答案1

同一个端口号可以一次用于 TCP,一次用于 UDP,并且它们在 IPv4 和 IPv6 上均存在。

TCP 和 UDP 端口号是完全不同的数字空间,它们恰好是成对分配的,并且需要两者的应用程序通常在每个端口上使用相同的数字。

IPv4 和 IPv6 是有些不同的协议;原则上,IPv6 应用程序可以接受 IPv4 连接,但通常认为拥有两个独立的套接字是一种好的做法。

答案2

netstat或输出中的每个条目lsof -i称为插座

每个插座都是由以下组合而成的:

  • 协议系列(例如 IPv4 或 IPv6)
  • 协议(例如 TCP 或 UDP)
  • 本地地址
  • 本地端口
  • 远程地址
  • 远程端口

这种变量组合称为连接元组

考虑ssh

如果您的机器正在运行,您将在输出中看到在端口上运行的服务器的sshd条目,该服务器正在监听并等待新的连接。netstat22

# netstat -tnl | grep 22
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN

但您还将看到每个活动连接的条目。

# netstat -tn
tcp        0      0 192.168.x.y:22          192.168.x.a:ppppp       ESTABLISHED
tcp        0      0 192.168.x.y:22          192.168.x.b:qqqqq       ESTABLISHED

因此上述输出表明端口22在同一台机器上被使用了3次。

在这种情况下,每个连接都是唯一的,因为每个连接都有不同的远程地址或端口。请注意,即使其中只有一个不同,它仍然使套接字唯一。

但它也可以通过本地地址或端口来唯一。

例如,你可以使用基于 Apache IP 的虚拟主机根据主机名或 IP 地址显示不同的站点:

# netstat -tnlp | grep 80
tcp        0      0 1.2.3.4:80              0.0.0.0:*               LISTEN      9876/apache2
tcp        0      0 1.2.3.5:80              0.0.0.0:*               LISTEN      9876/apache2

这里有两个套接字在监听端口 80。

在这个例子中,如果流量的目的地址是 1.2.3.4,它将被传送到第一个套接字;如果目的是 1.2.3.5,它将转到第二个套接字。

但是服务器必须明确执行此操作。服务器默认将本地地址设置为0.0.0.0,也写作*,这意味着该端口上只有一个监听套接字,它将接受该端口上的所有传入流量。

正如您所发现的,它对于每个协议来说也是唯一的。

例如,BIND DNS 服务器同时使用 TCP 和 UDP:

# netstat -nlp | grep named
tcp        0      0 127.0.0.1:53            0.0.0.0:*               LISTEN      567/named
tcp        0      0 192.168.x.y:53          0.0.0.0:*               LISTEN      567/named
tcp        0      0 127.0.0.1:953           0.0.0.0:*               LISTEN      567/named
udp        0      0 127.0.0.1:53            0.0.0.0:*                           567/named
udp        0      0 192.168.x.y:53          0.0.0.0:*                           567/named

每个协议系列的每个连接也是唯一的,这意味着 IPv4 和 IPv6 可以不同。

这取决于程序员要求的是仅 IPv4 套接字、仅 IPv6 套接字还是组合 IPv4/IPv6 套接字。

在 Linux 上,IPv6 套接字也会接受 IPv4 流量,除非程序员告诉它不要这样做,因此它只会在输出中出现一次netstat

$ port=55555
$ nc -6 -l $port || echo "Error listening on port $port" &
$ netstat -tnl | grep $port
tcp6       0      0 :::55555                :::*                    LISTEN     
$ nc -z 127.0.0.1 $port && echo "Port $port is accepting IPv4 connections"
Port 55555 is accepting IPv4 connections

memcached 源代码显示它明确要求仅 IPv6 套接字,这就是为什么 IPv4 和 IPv6 在您的示例中分别出现的原因。

error = setsockopt(sfd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &flags, sizeof(flags));

相关内容