检测断开的连接
本文关键字:连接 断开 检测 | 更新日期: 2023-09-27 17:53:30
我有一个服务器和许多客户端。服务器需要知道客户端何时不正常断开连接(不发送TCP FIN),这样它就不会有挂起的连接和其他与该客户端相关的一次性对象。
无论如何,我读了这篇文章,并决定从链接的博客中添加一个"保持存活消息到应用协议"(只包含头字节)和"显式定时器假设最坏"的方法。
当客户端连接时(顺便说一下,我使用tcpplistener和TcpClient),服务器启动一个System.Threading.Timer,倒计时30秒。每当服务器从该客户端接收到信息时,它就重置计时器。当timer达到0时,它断开用户的连接并释放它需要释放的东西。客户端应用程序也有一个计时器,当用户在15秒内没有发送任何东西(服务器值的一半,只是为了确保),它发送keepalive消息。
我的问题是,有更简单的方法来实现这一点吗?也许在TcpClient上有一些选项?我尝试使用TcpClient。ReceiveTimeout,但这似乎不与ReadAsync工作
正如Stephen指出的那样,在应用程序协议中使用心跳消息是确保连接是活动的并且两个应用程序都正确运行的唯一可靠方法。需要注意的是,许多工程师已经创建了一个心跳线程,即使在应用程序线程失败时,它也会继续运行。
使用这里的类将解决异步套接字问题。
public sealed class SocketAwaitable : INotifyCompletion
{
private readonly static Action SENTINEL = () => { };
internal bool m_wasCompleted;
internal Action m_continuation;
internal SocketAsyncEventArgs m_eventArgs;
public SocketAwaitable(SocketAsyncEventArgs eventArgs)
{
if (eventArgs == null) throw new ArgumentNullException("eventArgs");
m_eventArgs = eventArgs;
eventArgs.Completed += delegate
{
var prev = m_continuation ?? Interlocked.CompareExchange(
ref m_continuation, SENTINEL, null);
if (prev != null) prev();
};
}
internal void Reset()
{
m_wasCompleted = false;
m_continuation = null;
}
public SocketAwaitable GetAwaiter() { return this; }
public bool IsCompleted { get { return m_wasCompleted; } }
public void OnCompleted(Action continuation)
{
if (m_continuation == SENTINEL ||
Interlocked.CompareExchange(
ref m_continuation, continuation, null) == SENTINEL)
{
Task.Run(continuation);
}
}
public void GetResult()
{
if (m_eventArgs.SocketError != SocketError.Success)
throw new SocketException((int)m_eventArgs.SocketError);
}
}