似乎使用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,它抛出异常(试图调用被处置对象的方法)。 我的目标是为套接字连接阶段设置一个短暂的超时。
任何线索我做错了什么? 谢谢!
答案 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()你关闭旧的,在开始时你创建一个新的套接字,其参数与之前的套接字相同。