问题描述
林具有带TcpClient的与一个发送超时闭在多线程应用程序的连接已经打开之后的时间长时间(数小时或过夜)中的问题。所述的NetworkStream正在由两个线程,UI线程和后台线程。有用于读取输入的数据一个StreamReader,并用于输出数据的的StreamWriter。该StreamReader的是永远只能访问一个线程(背景之一),但StreamWriter的被UI线程和后台线程都访问。
什么情况是,如果我打开连接并连接到远程服务器,我可以立即发送和没有任何问题接收数据。我没有得到任何发送超时和数据被正确地发送和接收。但是,如果我再走开,不要几个小时发送任何数据,然后返回并开始发送数据(这是一个聊天应用程序如果这有助于使有意义),插座会超时的发送。在此期间,我走开存在一点问题都没有接收数据的时间。此外,对于活动连接远程服务器投票和我的客户必须向反应,而且由于连接是打开了几个小时就必须正确地发送响应。此轮询响应只发送在后台线程,虽然。数据输入我从UI线程发送的,而这也正是发生超时。
我猜这件事情做的并发访问,但我想不出什么导致它,为什么我最初从UI发送数据没有问题而只有在空闲几个小时后超时。
下面是相关的代码。顶部的变量在类中声明。地址和端口都在类的属性。的WriteLine是在任何地方,与StreamWriter的发送数据的应用程序的唯一方法。我把锁随时待命,以StreamWriter.WriteLine希望将纠正任何同步问题。的WriteLine从里面ParseMessage后台线程调用,并从其他地方UI
如果我增加TcpClient.SendTimeout更大的东西,不能解决任何事情。它只是需要更长的套接字超时。我不能有后台线程读取和写入,因为后台线程阻塞的ReadLine,所以没有什么会永远被写入。
私人TcpClient的_connection;
私人的StreamWriter _output;
私人螺纹_parsingThread;
私有对象_outputLock =新的对象();
公共无效连接(字符串的地址,端口INT)
{
地址=地址;
端口=端口;
_parsingThread =新主题(新的ThreadStart(运行));
_parsingThread.IsBackground = TRUE;
_parsingThread.Start();
}
私人无效的run()
{
试
{
使用(_connection =新的TcpClient())
{
_connection.Connect(地址,端口);
_connection.ReceiveTimeout = 180000;
_connection.SendTimeout = 60000;
StreamReader的输入=新的StreamReader(_connection.GetStream());
_output =新的StreamWriter(_connection.GetStream());
串线;
做
{
线= input.ReadLine();
如果(!string.IsNullOrEmpty(线))
{
ParseMessage(线);
}
}
,而(行!= NULL);
}
}
赶上(异常前)
{
//没有真正捕获的异常,只是压缩例如
}
终于
{
//东西
}
}
保护无效的WriteLine(串线)
{
锁(_outputLock)
{
_output.WriteLine(线);
_output.Flush();
}
}
的的的类没有被设计从多个同时使用线程。从MSDN:
My assumption is that, when you call WriteLine
(and, internally, NetworkStream.Write
) from your UI thread, it would block until the concurrent ReadLine
(internally, NetworkStream.Read
) operation completes in the background thread. If the latter does not do so within the SendTimeout
, then the Write
would time out.
To work around your issue, you should convert your implementation to use non-blocking methods. However, as a quick hack to first test whether this is really the issue, try introducing a DataAvailable
poll before your ReadLine
:
NetworkStream stream = _connection.GetStream();
StreamReader input = new StreamReader(stream);
_output = new StreamWriter(stream);
string line;
do
{
// Poll for data availability.
while (!stream.DataAvailable)
Thread.Sleep(300);
line = input.ReadLine();
if (!string.IsNullOrEmpty(line))
{
ParseMessage(line);
}
}
while (line != null);
line = input.ReadLine();
这篇关于多线程的TcpClient长开连接后发送超时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!