简体   繁体   English

如何判断Socket何时断开连接

[英]How to tell when a Socket has been disconnected

On the client side I need to know when/if my socket connection has been broken. 在客户端,我需要知道何时/如果我的套接字连接已被破坏。 However the Socket.Connected property always returns true, even after the server side has been disconnected and I've tried sending data through it. 但是,即使服务器端已断开连接并且我已尝试通过它发送数据,Socket.Connected属性也始终返回true。 Can anyone help me figure out what's going on here. 任何人都可以帮我弄清楚这里发生了什么。 I need to know when a socket has been disconnected. 我需要知道套接字何时断开连接。

        Socket serverSocket = null;
        TcpListener listener = new TcpListener(1530);
        listener.Start();
        listener.BeginAcceptSocket(new AsyncCallback(delegate(IAsyncResult result)
        {
            Debug.WriteLine("ACCEPTING SOCKET CONNECTION");
            TcpListener currentListener = (TcpListener)result.AsyncState;
            serverSocket = currentListener.EndAcceptSocket(result);
        }), listener);


        Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        Debug.WriteLine("client socket connected: " + clientSocket.Connected);//should be FALSE, and it is
        clientSocket.Connect("localhost", 1530);
        Debug.WriteLine("client socket connected: " + clientSocket.Connected);//should be TRUE, and it is

        Thread.Sleep(1000);
        serverSocket.Close();//closing the server socket here
        Thread.Sleep(1000);

        clientSocket.Send(new byte[0]);//sending data should cause the socket to update its Connected property.
        Debug.WriteLine("client socket connected: " + clientSocket.Connected);//should be FALSE, but its always TRUE

After doing some testing, it appears that the documentation for Socket.Connected is wrong, or at least misleading. 在进行一些测试之后,似乎Socket.Connected的文档是错误的,或者至少是误导性的。 clientSocket.Connected will only become false after clientSocket.close() is called. clientSocket.Connected只有在clientSocket.close()后才会变为false。 I think this is a throwback to the original C Berkeley sockets API and its terminology. 我认为这是原始C Berkeley套接字API及其术语的回归。 A socket is bound when it has a local address associated with it, and a socket is connected when it has a remote address associated with it. 当套接字具有与之关联的本地地址时绑定套接字,并且当套接字具有与之关联的远程地址时,将连接套接字。 Even though the remote side has closed the connection, the local socket still has the association and so it is still "connected". 即使远程端已关闭连接,本地套接字仍然具有关联,因此它仍然“连接”。

However, here is a method that does work: 然而,这里是工作的方法:

!(socket.Poll(0, SelectMode.SelectRead) && socket.Available == 0)

It relies on that fact that a closed connection will be marked as readable even though no data is available. 它依赖于这样一个事实:即使没有可用的数据,封闭连接也会被标记为可读。

If you want to detect conditions such as broken network cables or computers abruptly being turned off, the situation is a bit more complex. 如果要检测断开的网络电缆或计算机突然关闭等情况,情况会更复杂一些。 Under those conditions, your computer never receives a packet indicating that the socket has closed. 在这些情况下,您的计算机永远不会收到指示套接字已关闭的数据包。 It needs to detect that the remote side has vanished by sending packets and noticing that no response comes back. 它需要通过发送数据包并注意到没有响应返回来检测远程端已经消失。 You can do this at the application level as part of your protocol, or you can use the TCP KeepAlive option. 您可以在应用程序级别执行此操作作为协议的一部分,也可以使用TCP KeepAlive选项。 Using TCP Keep Alive from .NET isn't particularly easy; 使用.NET Keep Alive from .NET并不是特别容易; you're probably better off building a keep-alive mechanism into your protocol (alternately, you could ask a separate question for "How do I enable TCP Keep Alive in .NET and set the keep alive interval?"). 你可能最好在你的协议中构建一个保持活动机制(或者,你可以问一个单独的问题“如何在.NET中启用TCP保持活动并设置保持活动间隔?”)。

Just write to your socket as normal. 只需正常写入您的套接字。 You'll know when it's disconnected by the Exception that says your data couldn't be delivered. 您将知道什么时候它被异常断开,表示您的数据无法传递。

If you don't have anything to write...then who cares if it's disconnected? 如果你没有任何东西可以写...那么谁在乎它是否已断开连接? It may be disconnected now, but come back before you need it - why bother tearing it down, and then looping a reconnect until the link is repaired...especially when you didn't have anything to say anyway? 它现在可能已经断开连接,但在你需要它之​​前回来 - 为什么要把它拆掉,然后循环重新连接直到链接被修复...特别是当你没有任何要说的话时?

If it bothers you, implement a keep alive in your protocol. 如果它困扰你,请在你的协议中实现keep alive。 Then you'll have something to say every 30 seconds or so. 然后你会每30秒左右说一些话。

也许解决方案是通过它发送一些虚拟数据并检查它是否超时?

I recommend stripping out the higher-level language stuff and explore what happens at the lower-level IO. 我建议剥离更高级别的语言,并探索在低级IO中发生的事情。

The lowest I've explored was while writing isectd (find on sourceforge). 我探索的最低点是写作isectd(在sourceforge上找到)。 Using the select() system call, a descriptor for a closed socket becomes read-ready, and when isectd would attempt the recv() the socket's disconnected state can be confirmed. 使用select()系统调用,闭合套接字的描述符变为就绪,当isectd尝试recv()时,可以确认套接字的断开状态。

As a solution, I recommend not writing your own socket IO and use someone else's middleware. 作为一种解决方案,我建议不要编写自己的套接字IO并使用其他人的中间件。 There are lots of good candidates out there. 那里有很多优秀的候选人。 Don't forget to consider simple queuing services as well. 不要忘记考虑简单的排队服务。

PS. PS。 I would have provided URLs to all the above but my reputation (1) doesn't allow it. 我会提供以上所有的URL,但我的声誉(1)不允许。

does the clientSocket.Send() method wait for the packet to either be ack/nack'd? clientSocket.Send()方法是否等待数据包为ack / nack'd?

If not your code is flying onto the next line while socket is still trying to figure out what is going on. 如果不是你的代码飞到下一行,而socket仍在试图弄清楚发生了什么。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM