恢复计算机时线程不继续



我使用TcpClient.BeginConnect连接到客户端,只要不请求取消CancellationToken,我就有一个循环。

while (!_token.IsCancellationRequested)
{
var s = reader.ReadLine() ?? string.Empty;
}

我还通过日志记录重新连接和处理异常。

当我启动此应用程序时,一切都按预期工作。但是,当我将计算机置于睡眠状态并再次唤醒它时,似乎所有线程都已终止。

工作流程如下:

  1. 我(从主线程)启动一个新任务,该任务执行DoWork。我这样执行:Task.Run(()=>DoWork(),_token);
  2. DoWork实例化一个新TcpClient并启动如下所示的BeginConnect

(_client = new TcpClient()).BeginConnect(Address, Port, ConnectCallback, _client);

  1. ConnectCallback内,我有一个while语句,它不断从流中读取数据(见上文)。

知道计算机进入睡眠状态时线程会发生什么吗?

当您的计算机从睡眠状态唤醒时,连接有时会(但并非总是)被切断。这取决于许多因素,其中一些可能不受您的控制。

就回调方法而言,不会触发异常,但当连接结束且读取所有先前数据时reader.EndOfStream异常将为真。编辑:但是,如果 TCP 堆栈不知道远程已断开连接,则此调用将阻止,直到数据到达、TcpClient.ReceiveTimeout期已过或直到 TCP 会话空闲超时(以先发生者为准)。

(编辑:如果未发送任何数据,则仅当 TCP 堆栈知道(基于其自己的网络状态检测或 TCP 数据包)远程已断开连接时,连接才会自动结束;否则它将等到会话空闲超时,这可能需要长达一个小时左右,具体取决于客户端。一种解决方案是让客户端定期发送数据(如果它最近没有收到数据),以充当一种早期断开连接检测。

事实上,当连接结束时(例如,在您的计算机唤醒之后),您发布的while循环将进入一个紧密循环,使CPU内核最大化,因为reader.ReadLine()不断返回null。您可以检查这一点并脱离循环:

if (reader.EndOfStream)
{
break;
}

这个问题的解决方案(虽然不是一个很好的解决方案)是使用一个计时器,该计时器在给定的时间量后显式关闭连接。

var timeoutTimer = new Timer(state =>
{
var temp = (TcpClient)state;
Log.Error("Read timeout. Closing connection.");
temp.Close();
}, client, Timeout.Infinite, Timeout.Infinite);

在访问流之前,我激活了此计时器:

timeoutTimer.Change(20000, Timeout.Infinite); // Handle timeouts.

然后重置它:

timeoutTimer.Change(Timeout.Infinite, Timeout.Infinite); // Reset timeout.

两者都使用阅读器。EndOfStream 或 reader。ReadLine 会导致线程在该点停止,除非强制终止连接,否则不会解析。

编辑:设置TcpClient.ReceiveTimeout与上述相同 - 可能更好。当接收方在指定的时间量(以毫秒为单位)内未收到任何数据时,引发 IOException。

最新更新