我希望能得到一些关于在我正在研究的一篇文章中添加弹性的一些意见,其中涉及异步创建多个TcpClient连接到不同的服务器,一旦成功地建立了TCP连接,然后将TcpClient存储在某种集合中(这只是需求的一个摘录)。
到目前为止,这就是我所拥有的:
internal class Program
{
private static readonly TcpClient _client = new TcpClient(AddressFamily.InterNetwork);
private static SslStream _stream;
private static async Task Main(string[] args)
{
var timeoutTask = Task.Delay(5000);
var connectTask = _client.ConnectAsync("10.14.16.24", 56564);
var completedTask = await Task.WhenAny(timeoutTask, connectTask);
if (completedTask == timeoutTask)
_client.Dispose();
try
{
await connectTask;
_stream = new SslStream(_client.GetStream(), false);
}
catch (SocketException e)
{
Console.WriteLine(e.Message);
}
}
} returns :如果超时发生,connectTask状态仍然是"WaitingForActivation“,直到ConnectAsync方法返回Faulted或RanToCompletion为止。如何取消此任务,同时知道ConnectAsync不支持CancellationToken
欢迎任何建议或改进。谢谢
发布于 2019-08-15 21:09:07
您的里程可能因您使用的.net而异
using System;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
namespace TcpClientCancellation
{
public static class Extensions
{
public static async Task ConnectAsync(this TcpClient tcpClient, string host, int port, CancellationToken cancellationToken) {
if (tcpClient == null) {
throw new ArgumentNullException(nameof(tcpClient));
}
cancellationToken.ThrowIfCancellationRequested();
using (cancellationToken.Register(() => tcpClient.Close())) {
try {
cancellationToken.ThrowIfCancellationRequested();
await tcpClient.ConnectAsync(host, port).ConfigureAwait(false);
} catch (NullReferenceException) when (cancellationToken.IsCancellationRequested) {
cancellationToken.ThrowIfCancellationRequested();
}
}
}
}
}发布于 2021-03-16 14:03:06
作为@Kelly Elton答案的扩展,似乎您应该抓住
NullReferenceExceptionObjectDisposedException中SocketException中所以也许正确的catch语句应该是
#if NET5_0 //_OR_GREATER?
catch (SocketException ex) when (ct.IsCancellationRequested)
#elif NETCOREAPP2_0_OR_GREATER
catch (ObjectDisposedException ex) when (ct.IsCancellationRequested)
#elif NETFRAMEWORK && NET40_OR_GREATER
catch (NullReferenceException ex) when (ct.IsCancellationRequested)
#else
#error Untested target framework, use with care!
catch (???) when (ct.IsCancellationRequested)
#endif发布于 2021-08-31 17:32:03
我正在使用这些通用方法;它们可以为任何异步任务添加超时和取消令牌。您需要使用使用var tcpClient,以确保客户端在取消异常引发或主动释放客户端后被释放。
如果你看到任何问题,请告诉我,这样我就能相应地解决它。
public static async Task<T> RunTask<T>(Task<T> task, int timeout = 0, CancellationToken cancellationToken = default)
{
await RunTask((Task)task, timeout, cancellationToken);
return await task;
}
public static async Task RunTask(Task task, int timeout = 0, CancellationToken cancellationToken = default)
{
if (timeout == 0) timeout = -1;
var timeoutTask = Task.Delay(timeout, cancellationToken);
await Task.WhenAny(task, timeoutTask);
cancellationToken.ThrowIfCancellationRequested();
if (timeoutTask.IsCompleted)
throw new TimeoutException();
await task;
}使用
using var tcpClient = new TcpClient();
await RunTask(tcpClient.ConnectAsync("yourhost.com", 443), cancellationToken: CancellationToken.None);https://stackoverflow.com/questions/56193767
复制相似问题