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

r0u*_*u1i 11 c# sockets windows 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();
  }
Run Code Online (Sandbox Code Playgroud)

但是当我在循环完成后查看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
Run Code Online (Sandbox Code Playgroud)

编辑 .好的,缺少一些背景.我正在使用beginconnect,因为我希望套接字连接失败(9999未打开),并且在我的实际代码中,一旦设置了定时器,我就调用socket.Close().On OnSocketConnected我调用EndConnect,它抛出异常(试图调用被处置对象的方法).我的目标是为套接字连接阶段设置一个短暂的超时.

我有什么问题吗?谢谢!

Ed *_*fer 18

按照设计,你应该随时打电话 Shutdown在关闭套接字之前.

mySocket.Shutdown(SocketShutdown.Both);
mySocket.Close();
Run Code Online (Sandbox Code Playgroud)

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

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

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


nos*_*nos 14

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

  • 这是有道理的,但是不应该设置为false而应该解决它吗? (2认同)
  • @Jay:如果处理每次启动并启动新套接字时往往会选择相同目标端口号的TCP硬件,后一点可能会引起一些相当大的烦恼.如果连接发生时,设备将认为端口号不好并尝试新的端口号.但是,如果连接在FIN_WAIT中,则设备需要很长时间才能找到不合适的东西. (2认同)

Jon*_*eet 10

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

尝试同步连接 - 或关闭它,OnSocketConnected以便您可以看到关闭真正连接的插座的效果.