Я боролся с одной проблемой целых 3 дня. Не могу найти решение, пожалуйста, помогите:)
Я работаю с Visual Studio 2010 и языком C #.
У меня есть устройство, работающее как сервер, которое отправляет некоторые данные в очень нерегулярные периоды времени (невозможно определить время ожидания чтения).
Я написал TCP-клиент для подключения к этому серверу и чтения данных. Это работает нормально, однако, когда что-то не так с сетью и сервер становится недоступным (например, когда я подключаю сетевой кабель от моего компьютера), приложению требуется около 10 секунд, чтобы «заметить», что нет соединения с сервером и выдать исключение. (Я не знаю, почему именно 10 секунд? Где это определено? Могу ли я изменить это?)
Я хочу реагировать быстрее - скажем, через одну секунду после разрыва соединения.
Однако поиск ответа не дает мне никакого рабочего решения.
Тестовый код приведен ниже, я пытаюсь сделать его в 2 потоках: один читает данные, второй ищет состояние подключения и должен предупредить меня, когда он разорван. Это не работает ни для TCPClient, ни для класса Socket. Я пытался читать / записывать некоторые данные с tcpClient.SendTimeout = 100;
и stream.WriteTimeout = 100;
, но, похоже, это не сработало.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
namespace TCPClient
{
class Program
{
static volatile bool _continue = true;
static TcpClient tcpClient;
static NetworkStream stream;
static void Main(string[] args)
{
try
{
//client thread - listen from server
Thread tcpListenThread = new Thread(TcpListenThread);
tcpListenThread.Start();
//connection checking thread
Thread keepAliveThread = new Thread(KeepAliveThread);
keepAliveThread.Start();
while (_continue)
{
if (Console.ReadLine() == "q")
{
_continue = false;
}
}
keepAliveThread.Join(2000);
if (keepAliveThread.IsAlive)
{
Console.WriteLine("Thread keepAlive has been aborted...");
keepAliveThread.Abort();
}
tcpListenThread.Join(2000);
if (tcpListenThread.IsAlive)
{
Console.WriteLine("Listen thread has been aborted...");
tcpListenThread.Abort();
}
}
catch (Exception ex)
{
Console.WriteLine("\n" + ex.Message);
}
Console.WriteLine("\nHit any key to quit...");
Console.Read();
}
private static void TcpListenThread()
{
string server = "172.20.30.40";
int port = 3000;
try
{
using (tcpClient = new TcpClient())
{
tcpClient.Connect(server, port);
if (tcpClient.Connected)
Console.WriteLine("Successfully connected to server");
using (stream = tcpClient.GetStream())
{
while (_continue)
{
Byte[] data = new Byte[1024];
Int32 bytes = stream.Read(data, 0, data.Length);
string responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
Console.WriteLine("Received: {0}, responseData);
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Listen thread exception! " + ex.Message);
}
}
private static void KeepAliveThread()
{
while (_continue)
{
if (tcpClient != null)
{
try
{
//...what to put here to check or throw exception when server is not available??...
}
catch (Exception ex)
{
Console.WriteLine("Disconnected...");
}
}
Thread.Sleep(1000); //test for connection every 1000ms
}
}
}
}
Edit:
Ответ @ Carsten: хотя это выглядит многообещающе, это решение не работает ...
Я сделал простейшее тестовое приложение для этого:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
namespace TCPClientTest
{
class Program
{
static void Main(string[] args)
{
try
{
string server = "172.20.30.40";
int port = 3000;
using (TcpClient tcpClient = new TcpClient())
{
tcpClient.Connect(server, port);
int i = 0;
while (true)
{
// This is how you can determine whether a socket is still connected.
bool blockingState = tcpClient.Client.Blocking;
try
{
byte[] tmp = new byte[1];
tcpClient.Client.Blocking = false;
tcpClient.Client.Send(tmp, 0, 0);
Console.WriteLine("Connected!");
}
catch (SocketException e)
{
// 10035 == WSAEWOULDBLOCK
if (e.NativeErrorCode.Equals(10035))
Console.WriteLine("Still Connected, but the Send would block");
else
{
Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode);
}
}
finally
{
tcpClient.Client.Blocking = blockingState;
}
Console.WriteLine("Connected: {0} ({1})", tcpClient.Client.Connected, i++);
Thread.Sleep(1000);
}
}
}
catch (Exception ex)
{
Console.WriteLine("Global exception: {0}", ex.Message);
}
}
}
}
Результаты следующие, он отображает:
Connected!
Подключено: True
плюс мой номер заказа каждую секунду. Когда я отсоединяю сетевой кабель, для начала печати требуется 8 секунд:
Отключено: код ошибки 10054!
Подключено: False
так что через 8 секунд я не знаю, что соединение потеряно. Похоже, пинг - лучший вариант, но я опробую другие решения.