Socket.Close действительно не закрывает сокет tcp? (С#)
Кажется, что использование socket.Close() для сокета tcp не полностью закрывает сокет. В следующем примере я пытаюсь подключиться к example.com в порту 9999, который не открывается, и после короткого таймаута я пытаюсь закрыть сокет.
for (int i = 0; i < 200; i++)
{
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.LingerState = new LingerOption(false, 0);
sock.BeginConnect("www.example.com", 9999, OnSocketConnected, sock);
System.Threading.Thread.Sleep(50);
sock.Close();
}
Но когда я смотрю на netstat после завершения цикла, я обнаружил, что есть много полуоткрытых сокетов:
TCP israel-xp:6506 www.example.com:9999 SYN_SENT
TCP israel-xp:6507 www.example.com:9999 SYN_SENT
TCP israel-xp:6508 www.example.com:9999 SYN_SENT
TCP israel-xp:6509 www.example.com:9999 SYN_SENT
ИЗМЕНИТЬ
,
Хорошо, какой-то контекст отсутствовал. Я использую beginconnect, потому что ожидаю, что соединение сокета завершится неудачно (9999 не открывается), и в моем реальном коде я вызываю socket.Close() как только установлен таймер.
В OnSocketConnected я вызываю EndConnect, который генерирует исключение (пытается вызвать метод расположенного объекта).
Моя цель - короткий тайм-аут для этапа подключения сокета.
Любые подсказки, что я делаю неправильно?
Спасибо!
Ответы
Ответ 1
Он закроет .NET-часть сокета. Однако в соответствии со спецификацией TCP ОС должна поддерживать более низкий уровень латентности сокета открытым в течение определенного времени, чтобы обнаружить повторную передачу и тому подобное. В этом конкретном случае он, скорее всего, поддерживает сокет вокруг немного, чтобы обнаружить ответ на отправленный SYN-пакет, чтобы он мог более разумно ответить и не смешивать ответ с отправленными пакетами.
Ответ 2
По дизайну вы должны всегда вызывать Shutdown
перед закрытием сокета.
mySocket.Shutdown(SocketShutdown.Both);
mySocket.Close();
Эффективно отключает отправку и получение в сокете, поэтому он не будет принимать входящие данные после его закрытия, даже если ОС все еще контролирует его.
Джон Скит также имеет точку зрения, что, поскольку вы открываете соединение асинхронно, он может фактически подключаться, когда вы пытаетесь его закрыть. Однако, если вы вызываете Shutdown
на нем, это не позволит получать информацию, как вы переживаете.
Изменить: Вы можете только Shutdown
сокет, который уже подключен, поэтому помните об этом, когда пишете свой код.
Ответ 3
Вы вызываете *Begin*Connect
- так делаете это асинхронно. Вероятно, вы пытаетесь закрыть сокет, прежде чем он будет подключен, поэтому когда он подключается, он остается открытым.
Попробуйте подключиться синхронно - или закрыть его в OnSocketConnected
, чтобы вы могли увидеть эффект закрытия действительно подключенного сокета.
Ответ 4
Вы инициализируете новый Socket в каждом цикле... с *.close(), вы закрываете старое, и в начале вы создаете новый с теми же параметрами, что и Socket раньше.