问题
I'd like to have an asynchronous continuous ping request on a ip + port. The problem is, when the targeted server is offline, the whole program freezes during request time. But this shouldn't happen.
This is my ping function which is called once when starting the program. It should do a ping request every 3 seconds.
public async void Start(string ip)
{
Stopwatch watch = new Stopwatch();
while (true)
{
watch.Restart();
using (TcpClient tcp = new TcpClient())
{
//try to connect to a closed port
IAsyncResult res = tcp.ConnectAsync("127.0.0.1", 1234);
//during the following while-loop the whole program freezes
//although this is an asynchronous function
while (watch.ElapsedMilliseconds < 1000)
{
if (tcp.Connected)
{
break;
}
}
watch.Stop();
if (tcp.Connected)
{
StatusControl.Text = watch.ElapsedMilliseconds.ToString() + " ms";
}
else
{
StatusControl.Text = "Offline";
}
}
//wait 3secs for the next request
await Task.Delay(3000);
}
}
回答1:
If you want your application to remain responsive and not hang, you cannot build your own loop and keep the thread occupied. Instead, let C# take care of managing the Task for you by using the await
keyword. Instead of looping and checking for timeout, just set a timeout on the request using SendTimeout
. Here is an example:
public async void Start(string ip)
{
label1.Text = "Begin";
Stopwatch watch = new Stopwatch();
while (true)
{
watch.Restart();
using (TcpClient tcp = new TcpClient())
{
//try to connect to a closed port
// First set a timeout value
tcp.SendTimeout = 1000;
try
{
await tcp.ConnectAsync("127.0.0.1", 1234);
}
catch (SocketException)
{
Debug.Assert(!tcp.Connected);
}
watch.Stop();
if (tcp.Connected)
{
label1.Text = watch.ElapsedMilliseconds.ToString() + " ms";
}
else
{
label1.Text = "Offline";
}
}
//wait 3secs for the next request
await Task.Delay(3000);
}
}
}
回答2:
If you want to do an asynchronous ping request to a port along with a timeout, this code did it for me:
private async Task<long> Ping(string host, int port, int timeOut)
{
long elapsed = -1;
Stopwatch watch = new Stopwatch();
using (TcpClient tcp = new TcpClient())
{
try
{
using (CancellationTokenSource cts = new CancellationTokenSource())
{
StartConnection(host, port, tcp, watch, cts);
await Task.Delay(timeOut, cts.Token);
}
}
catch {}
finally
{
if (tcp.Connected)
{
tcp.GetStream().Close();
elapsed = watch.ElapsedMilliseconds;
}
tcp.Close();
}
}
return elapsed;
}
private async void StartConnection(string host, int port, TcpClient tcp, Stopwatch watch, CancellationTokenSource cts)
{
try
{
watch.Start();
await tcp.ConnectAsync(host,port);
watch.Stop();
cts.Cancel();
}
catch {}
}
It simply disposes the tcpClient as soon as the time is over and returns -1 when the server is offline or something went wrong.
来源:https://stackoverflow.com/questions/28729662/tcp-client-connection-freezes-program