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 раньше.