我在連接打開很長一段時間(幾個小時或一夜之間)之後,在多線程應用程序中發送超時時發生TcpClient關閉時出現問題)。 NetworkStream被兩個線程(UI線程和後臺線程)使用。有一個StreamReader用於讀取傳入數據,以及一個StreamWriter用於傳出數據。 StreamReader只能訪問一個線程(後臺線程),但StreamWriter可以被UI線程和後臺線程訪問。多線程TcpClient在長時間打開連接後發送超時
會發生什麼情況是,如果我打開連接並連接到遠程服務器,我可以立即發送和接收數據,沒有任何問題。我沒有收到任何發送超時,並且數據正確發送和接收。但是,如果我隨後離開並且幾個小時不發送任何數據,然後返回並開始發送數據(如果這有助於使其有意義,則這是一個聊天應用程序),套接字將在發送時超時。在我離開的時候,所有接收數據都沒有問題。另外,遠程服務器輪詢正在進行的連接,並且我的客戶端必須對此作出響應,並且由於連接已打開幾個小時,它必須正確發送響應。不過,該輪詢響應僅在後臺線程上發送。我輸入的數據從UI線程發送,這就是超時發生的地方。
我猜這是與併發訪問有關,但我無法弄清楚是什麼導致它,以及爲什麼我最初可以從UI發送數據而沒有問題,並且只有在閒置幾個小時後纔會超時。
下面是相關的代碼。頂部的變量在類中聲明。地址和端口是類中的屬性。 WriteLine是應用程序中使用StreamWriter發送數據的唯一方法。我把鎖定在StreamWriter.WriteLine的調用上,希望能糾正任何同步問題。 WriteLine是從ParseMessage內部的後臺線程以及UI中的其他地方調用的。
如果我增加TcpClient.SendTimeout到更大的東西,那不解決任何問題。套接字超時需要更長的時間。我不能讓後臺線程讀取和寫入,因爲後臺線程在ReadLine上阻塞,所以什麼也不會寫入。
private TcpClient _connection;
private StreamWriter _output;
private Thread _parsingThread;
private object _outputLock = new object();
public void Connect(string address, int port)
{
Address = address;
Port = port;
_parsingThread = new Thread(new ThreadStart(Run));
_parsingThread.IsBackground = true;
_parsingThread.Start();
}
private void Run()
{
try
{
using (_connection = new TcpClient())
{
_connection.Connect(Address, Port);
_connection.ReceiveTimeout = 180000;
_connection.SendTimeout = 60000;
StreamReader input = new StreamReader(_connection.GetStream());
_output = new StreamWriter(_connection.GetStream());
string line;
do
{
line = input.ReadLine();
if (!string.IsNullOrEmpty(line))
{
ParseMessage(line);
}
}
while (line != null);
}
}
catch (Exception ex)
{
//not actually catching exception, just compressing example
}
finally
{
//stuff
}
}
protected void WriteLine(string line)
{
lock (_outputLock)
{
_output.WriteLine(line);
_output.Flush();
}
}