Каждая запись в выводе netstat
или lsof -i
называется сокетом.
Каждая розетка сделана уникальной благодаря комбинации:
- семейство протоколов (например, IPv4 или IPv6)
- протокол (например, TCP или UDP)
- местный адрес
- местный порт
- удаленный адрес
- удаленный порт
Эта комбинация переменных называется кортежем соединения.
Рассмотрим ssh
.
Если на вашей машине запущен sshd
, вы увидите запись в выводе netstat
для сервера, работающего на порту 22
, который прослушивает и ждет новых подключений.
# 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
, также записанный *
, что означает, что на этом порту будет только один прослушивающий сокет, и он будет принимать весь входящий трафик на этом порту.
Как вы обнаружили, он также уникален для каждого протокола.
Например, DNS-сервер BIND использует 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));