Each entry in the
lsof -i output is called a socket.
Each socket is made unique by a combination of:
- protocol family (e.g. IPv4 or IPv6)
- protocol (e.g. TCP or UDP)
- local address
- local port
- remote address
- remote port
This combination of variables is called the connection tuple.
If your machine is running
sshd, you will see an entry in the
netstat output for the server that is running on port
22, listening and waiting for new connections.
# netstat -tnl | grep 22
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
But you will also see entries for each active connection.
# 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
So the above output shows port
22 is being used 3 times on the same machine.
In this case, each connection is unique because each one has a different remote address or port. Note that even if only one of those is different, it still makes the socket unique.
But it can also be unique by local address or port.
For example, you could be using Apache IP-based virtual hosts to show a different site depending on the host name or IP address:
# netstat -tnlp | grep 80
tcp 0 0 184.108.40.206:80 0.0.0.0:* LISTEN 9876/apache2
tcp 0 0 220.127.116.11:80 0.0.0.0:* LISTEN 9876/apache2
Here, there are two sockets listening on port 80.
In this example, if traffic comes in with a destination address of 18.104.22.168, it will be delivered to the first socket; if the destination is 22.214.171.124 it goes to the second one.
The server has to do this explicitly however. The default for a server is to set the local address to
0.0.0.0, also written
*, which means there will only be one listening socket on that port, and it will accept all incoming traffic on that port.
As you have discovered, it is also unique per protocol.
For example, the BIND DNS server uses both TCP and 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
Each connection is also unique per protocol family, meaning IPv4 and IPv6 can be distinct.
This depends on whether the programmer asked for an IPv4-only socket, an IPv6-only socket, or a combined IPv4/IPv6 socket.
On Linux an IPv6 socket also accepts IPv4 traffic unless the programmer tells it not to, and therefore only appears once in the
$ 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
But the memcached source code shows it is explicitly asking for an IPv6-only socket, which is why IPv4 and IPv6 appear separately in your example.
error = setsockopt(sfd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &flags, sizeof(flags));