TCP连接由以下元组唯一标识:(本地地址,本地端口号,远程地址,远程端口号)
。并没有要求本地地址
和远程地址
必须不同或者端口号必须不同(尽管这可能非常奇怪)。但对于给定元组的相同值,最多只有1个TCP连接。
当计算机与自己连接时,它的本地地址和远程地址几乎总是相同的。毕竟,“本地”端和“远程”端实际上是同一台计算机。事实上,当这种情况发生时,您的计算机应该显示两个具有相同“本地”和“远程”地址,但端口号相反的连接。例如:
$ ssh localhost
这将导致类似于以下两个连接:
$ netstat -nA inet | fgrep :22
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.1:56039 127.0.0.1:22 ESTABLISHED
tcp 0 0 127.0.0.1:22 127.0.0.1:56039 ESTABLISHED
从上面可以看到,本地地址和远程地址是相同的,但是端口号是颠倒的。这个TCP连接的唯一元组是 (127.0.0.1, 56039, 127.0.0.1, 22)
。不会有其他具有相同四个字段的TCP连接。
你看到两个地址的原因是因为你的计算机是连接的两端。每一端都有自己关于哪一个是“外部的”和“本地的”的视角。
你甚至可以在相同的端口上连接到自己,虽然这不是很常见,但是它在规范上也不被禁止。这里是一个用Python编写的示例程序:
import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 56443))
s.connect(('127.0.0.1', 56443))
time.sleep(30)
这段代码可行的原因是打开TCP连接的一种方式是让连接的另一端同时尝试与你打开连接。这被称为同时SYN交换,链接到StackOverflow答案描述了这个过程。
我还有一篇关于使用同时SYN交换穿越NAT的论文,但在那种情况下,源和外部会完全不同。