Как вы можете подключить TCP-порт к одному и тому же порту?
Машина - RHEL 5.3 (ядро 2.6.18).
Несколько раз я замечаю в netstat, что мое приложение имеет соединение, установлено TCP-соединение, когда локальный адрес и иностранный адрес совпадают.
Здесь та же проблема, о которой сообщает и кто-то еще.
Симптомы те же, что описаны в ссылке - клиент подключается к порту порта порта, работающему локально. Через некоторое время netstat показывает, что клиент имеет соединение от 127.0.0.1:X
до 127.0.0.1:X
Как это возможно?
Изменить 01
Одновременное открытие вызывает проблему (большое спасибо Хастуркуну). Вы можете увидеть его на классической диаграмме состояний TCP при переходе из состояния SYN_SENT в SYNC_RECEIVED
Ответы
Ответ 1
Это может быть вызвано одновременным подключением TCP (упомянутый в этом сообщении для LKML, см. также здесь).
Возможно, что цикл программы пытается подключиться к порту в диапазоне динамического локального порта (который можно увидеть в /proc/sys/net/ipv4/ip_local_port_range
), чтобы преуспеть, пока сервер не прослушивает этот порт.
При достаточно большом количестве попыток сокет, используемый для соединения, может быть привязан к тому же порту, к которому подключен, что удается из-за ранее упомянутого одновременного соединения. Теперь у вас волшебный клиент, подключенный к себе
Ответ 2
TCP-соединение однозначно идентифицируется с помощью этого набора (local address, local port #, foreign address, foreign port #)
. Нет требования, чтобы local address
и foreign address
, или даже номера портов были разными (хотя это было бы чрезвычайно странно). Но есть не более одного 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, хотя в этом случае исходный и чуждый были бы совершенно разными.