msb*_*sbg 68 c# networking tcpclient winforms
我有一个TcpClient,我用它来发送数据到远程计算机上的监听器.远程计算机有时会打开,有时会关闭.因此,TcpClient将无法经常连接.我希望TcpClient在一秒钟后超时,因此它无法连接到远程计算机时花费太多时间.目前,我将此代码用于TcpClient:
try
{
TcpClient client = new TcpClient("remotehost", this.Port);
client.SendTimeout = 1000;
Byte[] data = System.Text.Encoding.Unicode.GetBytes(this.Message);
NetworkStream stream = client.GetStream();
stream.Write(data, 0, data.Length);
data = new Byte[512];
Int32 bytes = stream.Read(data, 0, data.Length);
this.Response = System.Text.Encoding.Unicode.GetString(data, 0, bytes);
stream.Close();
client.Close();
FireSentEvent(); //Notifies of success
}
catch (Exception ex)
{
FireFailedEvent(ex); //Notifies of failure
}
Run Code Online (Sandbox Code Playgroud)
这对于处理任务非常有效.如果可以,它会发送它,如果它无法连接到远程计算机,则捕获异常.但是,当它无法连接时,抛出异常需要十到十五秒.我需要它在大约一秒钟内超时?我怎样才能改变超时时间?
Jon*_*Jon 83
您需要使用异步BeginConnect方法TcpClient而不是尝试同步连接,这是构造函数的作用.像这样的东西:
var client = new TcpClient();
var result = client.BeginConnect("remotehost", this.Port, null, null);
var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));
if (!success)
{
throw new Exception("Failed to connect.");
}
// we have connected
client.EndConnect(result);
Run Code Online (Sandbox Code Playgroud)
Sim*_*ier 73
从.NET 4.5开始,TcpClient有一个很酷的ConnectAsync方法,我们可以像这样使用,所以它现在非常简单:
var client = new TcpClient();
if (!client.ConnectAsync("remotehost", remotePort).Wait(1000))
{
// connection failure
}
Run Code Online (Sandbox Code Playgroud)
小智 12
使用/sf/answers/1797918461/的另一种方法:
var timeOut = TimeSpan.FromSeconds(5);
var cancellationCompletionSource = new TaskCompletionSource<bool>();
try
{
using (var cts = new CancellationTokenSource(timeOut))
{
using (var client = new TcpClient())
{
var task = client.ConnectAsync(hostUri, portNumber);
using (cts.Token.Register(() => cancellationCompletionSource.TrySetResult(true)))
{
if (task != await Task.WhenAny(task, cancellationCompletionSource.Task))
{
throw new OperationCanceledException(cts.Token);
}
}
...
}
}
}
catch(OperationCanceledException)
{
...
}
Run Code Online (Sandbox Code Playgroud)
需要注意的一点是,在超时到期之前,BeginConnect调用可能会失败.如果您尝试本地连接,可能会发生这种情况.这是Jon的代码的修改版本......
var client = new TcpClient();
var result = client.BeginConnect("remotehost", Port, null, null);
result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));
if (!client.Connected)
{
throw new Exception("Failed to connect.");
}
// we have connected
client.EndConnect(result);
Run Code Online (Sandbox Code Playgroud)
上面的答案不包括如何干净地处理已超时的连接.调用TcpClient.EndConnect,关闭超时后成功的连接,并处理TcpClient.
这可能有点矫枉过正,但这对我有用.
private class State
{
public TcpClient Client { get; set; }
public bool Success { get; set; }
}
public TcpClient Connect(string hostName, int port, int timeout)
{
var client = new TcpClient();
//when the connection completes before the timeout it will cause a race
//we want EndConnect to always treat the connection as successful if it wins
var state = new State { Client = client, Success = true };
IAsyncResult ar = client.BeginConnect(hostName, port, EndConnect, state);
state.Success = ar.AsyncWaitHandle.WaitOne(timeout, false);
if (!state.Success || !client.Connected)
throw new Exception("Failed to connect.");
return client;
}
void EndConnect(IAsyncResult ar)
{
var state = (State)ar.AsyncState;
TcpClient client = state.Client;
try
{
client.EndConnect(ar);
}
catch { }
if (client.Connected && state.Success)
return;
client.Close();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
83526 次 |
| 最近记录: |