Socket.Close没有真正关闭tcp套接字? (C#)

时间:2010-01-06 17:33:29

标签: c# windows sockets tcp

似乎使用socket.Close()作为tcp套接字,并没有完全关闭套接字。在下面的示例中,我尝试在未打开的端口9999处连接到example.com,并且在短暂超时之后,我正在尝试关闭套接字。

  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()。 On OnSocketConnected我调用EndConnect,它抛出异常(试图调用被处置对象的方法)。 我的目标是为套接字连接阶段设置一个短暂的超时。

任何线索我做错了什么? 谢谢!

4 个答案:

答案 0 :(得分:18)

按照设计,您应该在关闭套接字之前调用Shutdown

mySocket.Shutdown(SocketShutdown.Both);
mySocket.Close();

这样做可以有效地禁用套接字上的发送和接收,因此即使操作系统仍然可以控制它,它也不会在关闭后接受传入数据。

Jon Skeet也有一个观点,即由于您是异步打开连接,因此当您尝试关闭它时,它实际上可能正在连接。但是,如果您在其上拨打Shutdown,则不会在您遇到时接收信息。

编辑:您只能Shutdown已连接的套接字,因此在编写代码时请记住这一点。

答案 1 :(得分:14)

它将关闭套接字的.NET部分。然而,根据TCP规范,OS必须将套接字的较低级别花絮保持打开一段时间以便检测重传,并且类似。在这种特殊情况下,为了检测对发送的SYN数据包的回复,可能会将套接字保持一段时间,这样它可以更明智地回复,而不会将回复与发送的其他数据包混淆。

答案 2 :(得分:10)

您正在调用*Begin*Connect - 所以异步执行此操作。您很可能在连接之前尝试关闭套接字 - 所以当它连接时,它仍保持打开状态。

尝试同步连接 - 或在OnSocketConnected中关闭它,这样您就可以看到关闭真正连接的套接字的效果。

答案 3 :(得分:0)

你正在每个循环中初始化一个新的套接字...用* .close()你关闭旧的,在开始时你创建一个新的套接字,其参数与之前的套接字相同。