C# 立即检测客户端与服务器套接字的断开连接
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/722240/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Instantly detect client disconnection from server socket
提问by
How can I detect that a client has disconnected from my server?
如何检测客户端与我的服务器断开连接?
I have the following code in my AcceptCallBack
method
我有下面的代码在我的AcceptCallBack
方法
static Socket handler = null;
public static void AcceptCallback(IAsyncResult ar)
{
//Accept incoming connection
Socket listener = (Socket)ar.AsyncState;
handler = listener.EndAccept(ar);
}
I need to find a way to discover as soon as possible that the client has disconnected from the handler
Socket.
我需要找到一种方法来尽快发现客户端已与handler
Socket断开连接。
I've tried:
我试过了:
handler.Available;
handler.Send(new byte[1], 0, SocketFlags.None);
handler.Receive(new byte[1], 0, SocketFlags.None);
handler.Available;
handler.Send(new byte[1], 0, SocketFlags.None);
handler.Receive(new byte[1], 0, SocketFlags.None);
The above approaches work when you are connecting to a server and want to detect when the server disconnects but they do not work when you are the server and want to detect client disconnection.
当您连接到服务器并希望检测服务器何时断开连接时,上述方法有效,但当您是服务器并希望检测客户端断开连接时,它们不起作用。
Any help will be appreciated.
任何帮助将不胜感激。
采纳答案by Samuel
Since there are no events available to signal when the socket is disconnected, you will have to poll it at a frequency that is acceptable to you.
由于在套接字断开连接时没有可用于发出信号的事件,因此您必须以您可以接受的频率对其进行轮询。
Using this extension method, you can have a reliable method to detect if a socket is disconnected.
使用这种扩展方法,您可以有一种可靠的方法来检测套接字是否断开连接。
static class SocketExtensions
{
public static bool IsConnected(this Socket socket)
{
try
{
return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
}
catch (SocketException) { return false; }
}
}
回答by Erik Funkenbusch
This is simply not possible. There is no physical connection between you and the server (except in the extremely rare case where you are connecting between two compuers with a loopback cable).
这根本不可能。您和服务器之间没有物理连接(除非在极少数情况下您使用环回电缆连接两台计算机)。
When the connection is closed gracefully, the other side is notified. But if the connection is disconnected some other way (say the users connection is dropped) then the server won't know until it times out (or tries to write to the connection and the ack times out). That's just the way TCP works and you have to live with it.
当连接正常关闭时,通知另一方。但是,如果连接以其他方式断开(假设用户连接断开),那么服务器将不知道,直到它超时(或尝试写入连接并且 ack 超时)。这就是 TCP 的工作方式,您必须接受它。
Therefore, "instantly" is unrealistic. The best you can do is within the timeout period, which depends on the platform the code is running on.
因此,“立即”是不现实的。您能做的最好的事情是在超时期限内,这取决于运行代码的平台。
EDIT: If you are only looking for graceful connections, then why not just send a "DISCONNECT" command to the server from your client?
编辑:如果你只是在寻找优雅的连接,那么为什么不从你的客户端向服务器发送一个“DISCONNECT”命令呢?
回答by theG
You can also check the .IsConnected property of the socket if you were to poll.
如果要轮询,还可以检查套接字的 .IsConnected 属性。
回答by Niran
Implementing heartbeat into your system might be a solution. This is only possible if both client and server are under your control. You can have a DateTime object keeping track of the time when the last bytes were received from the socket. And assume that the socket not responded over a certain interval are lost. This will only work if you have heartbeat/custom keep alive implemented.
在您的系统中实施心跳可能是一个解决方案。这只有在客户端和服务器都在您的控制之下时才有可能。您可以让 DateTime 对象跟踪从套接字接收到最后一个字节的时间。并假设在特定时间间隔内未响应的套接字丢失。这仅在您实现了心跳/自定义保持活动时才有效。
回答by Aditya Sehgal
Can't you just use Select?
你不能只使用 Select 吗?
Use select on a connected socket. If the select returns with your socket as Ready but the subsequent Receive returns 0 bytes that means the client disconnected the connection. AFAIK, that is the fastest way to determine if the client disconnected.
在连接的套接字上使用 select。如果选择返回时您的套接字为就绪,但随后的接收返回 0 字节,这意味着客户端断开了连接。AFAIK,这是确定客户端是否断开连接的最快方法。
I do not know C# so just ignore if my solution does not fit in C# (C# does provide selectthough) or if I had misunderstood the context.
我不知道 C#,所以如果我的解决方案不适合 C#(尽管C# 确实提供了选择)或者我是否误解了上下文,请忽略。
回答by ATC
"That's just the way TCP works and you have to live with it."
“这就是 TCP 的工作方式,你必须接受它。”
Yup, you're right. It's a fact of life I've come to realize. You will see the same behavior exhibited even in professional applications utilizing this protocol (and even others). I've even seen it occur in online games; you're buddy says "goodbye", and he appears to be online for another 1-2 minutes until the server "cleans house".
是的,你说得对。这是我逐渐意识到的生活事实。即使在使用此协议(甚至其他协议)的专业应用程序中,您也会看到相同的行为。我什至看到它发生在网络游戏中;你的好友说“再见”,他似乎又在线了 1-2 分钟,直到服务器“打扫房间”。
You can use the suggested methods here, or implement a "heartbeat", as also suggested. I choose the former. But if I did choose the latter, I'd simply have the server "ping" each client every so often with a single byte, and see if we have a timeout or no response. You could even use a background thread to achieve this with precise timing. Maybe even a combination could be implemented in some sort of options list (enum flags or something) if you're really worried about it. But it's no so big a deal to have a little delay in updating the server, as long as you DO update. It's the internet, and no one expects it to be magic! :)
您可以在此处使用建议的方法,也可以按照建议实施“心跳”。我选择前者。但是,如果我确实选择了后者,我只需让服务器每隔一个字节就“ping”每个客户端,看看我们是否有超时或没有响应。您甚至可以使用后台线程以精确的时间实现这一点。如果您真的很担心,甚至可以在某种选项列表(枚举标志或其他东西)中实现组合。但是,只要您确实更新,更新服务器的延迟就没什么大不了的。这是互联网,没有人期望它是魔术!:)
回答by ATC
I've found quite useful, another workaround for that!
我发现它非常有用,这是另一种解决方法!
If you use asynchronous methods for reading data from the network socket (I mean, use BeginReceive
- EndReceive
methods), whenever a connection is terminated; one of these situations appear: Either a message is sent with no data (you can see it with Socket.Available
- even though BeginReceive
is triggered, its value will be zero) or Socket.Connected
value becomes false in this call (don't try to use EndReceive
then).
如果您使用异步方法从网络套接字读取数据(我的意思是使用BeginReceive
-EndReceive
方法),则无论何时终止连接;出现以下情况之一:要么发送没有数据的消息(您可以看到它Socket.Available
- 即使BeginReceive
被触发,其值也将为零)或Socket.Connected
值在此调用中变为假(EndReceive
然后不要尝试使用)。
I'm posting the function I used, I think you can see what I meant from it better:
我发布了我使用的函数,我想你可以更好地理解我的意思:
private void OnRecieve(IAsyncResult parameter)
{
Socket sock = (Socket)parameter.AsyncState;
if(!sock.Connected || sock.Available == 0)
{
// Connection is terminated, either by force or willingly
return;
}
sock.EndReceive(parameter);
sock.BeginReceive(..., ... , ... , ..., new AsyncCallback(OnRecieve), sock);
// To handle further commands sent by client.
// "..." zones might change in your code.
}
回答by Bassem
The example code here http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.connected.aspxshows how to determine whether the Socket is still connected without sending any data.
此处的示例代码 http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.connected.aspx显示了如何在不发送任何数据的情况下确定 Socket 是否仍然连接。
If you called Socket.BeginReceive() on the server program and then the client closed the connection "gracefully", your receive callback will be called and EndReceive() will return 0 bytes. These 0 bytes mean that the client "may" have disconnected. You can then use the technique shown in the MSDN example code to determine for sure whether the connection was closed.
如果您在服务器程序上调用 Socket.BeginReceive() 然后客户端“正常”关闭连接,您的接收回调将被调用并且 EndReceive() 将返回 0 字节。这些 0 字节意味着客户端“可能”已断开连接。然后,您可以使用 MSDN 示例代码中显示的技术来确定连接是否已关闭。
回答by Rama
Using the method SetSocketOption, you will be able to set KeepAlive that will let you know whenever a Socket gets disconnected
使用 SetSocketOption 方法,您将能够设置 KeepAlive,它会在 Socket 断开连接时通知您
Socket _connectedSocket = this._sSocketEscucha.EndAccept(asyn);
_connectedSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, 1);
http://msdn.microsoft.com/en-us/library/1011kecd(v=VS.90).aspx
http://msdn.microsoft.com/en-us/library/1011kecd(v=VS.90).aspx
Hope it helps! Ramiro Rinaldi
希望能帮助到你!拉米罗·里纳尔迪
回答by JJ_Coder4Hire
This worked for me, the key is you need a separate thread to analyze the socket state with polling. doing it in the same thread as the socket fails detection.
这对我有用,关键是您需要一个单独的线程来通过轮询分析套接字状态。在与套接字失败检测相同的线程中执行此操作。
//open or receive a server socket - TODO your code here
socket = new Socket(....);
//enable the keep alive so we can detect closure
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
//create a thread that checks every 5 seconds if the socket is still connected. TODO add your thread starting code
void MonitorSocketsForClosureWorker() {
DateTime nextCheckTime = DateTime.Now.AddSeconds(5);
while (!exitSystem) {
if (nextCheckTime < DateTime.Now) {
try {
if (socket!=null) {
if(socket.Poll(5000, SelectMode.SelectRead) && socket.Available == 0) {
//socket not connected, close it if it's still running
socket.Close();
socket = null;
} else {
//socket still connected
}
}
} catch {
socket.Close();
} finally {
nextCheckTime = DateTime.Now.AddSeconds(5);
}
}
Thread.Sleep(1000);
}
}