与TcpClient的多个连接,第二个连接始终挂起/不执行任何操作

时间:2018-11-24 01:24:16

标签: c# .net .net-core tcpclient tcplistener

因此,我在正在监听端口9096的控制台应用程序中有一个TcpClient。我希望客户端能够处理多个连接(同时或不同时)。我也不想使用线程。我想使用异步/等待。在某些事件中,我还需要能够正常关闭应用程序,请注意不要丢失任何数据。所以我需要一个取消令牌。我的代码大部分都能正常工作,但是有两个问题。

首先,当应用开始监听并发送数据时;只要发件人使用与应用程序相同的初始连接,一切都可以正常工作。一旦建立了新的连接(或我想知道的套接字?在术语上不清楚),应用程序就不会处理新数据。

第二,当向应用程序发出终止信号并且令牌被取消时,应用程序不会关闭。我没有任何例外,也无法弄清楚自己在做什么错。

我四处张望,找不到使用带有取消令牌的async / await的TcpClient的示例。我也找不到一个示例,说明我能够使用多个线程或其他复杂的设计来正确处理多个连接。我希望设计尽可能简单,代码尽可能少,同时又能满足我的要求。如果使用线程是唯一的方法,那么我会做,但是我已经很接近正确了,我觉得我只是缺少了一点东西。

我竭尽全力试图解决这个问题,并耗尽了我所有的想法。

编辑:我按照以下建议将AcceptTcpClientAsync移到了循环中,它没有任何改变。应用程序的功能与以前相同。

Program.cs

class Program
{
    private static List<Task> _listeners = new List<Task>();
    private static readonly CancellationTokenSource cancelSource = new CancellationTokenSource();

    static void Main(string[] args)
    {
        Console.TreatControlCAsInput = false;
        Console.CancelKeyPress += (o, e) => {
            Console.WriteLine("Shutting down.");
            cancelSource.Cancel();
        };            

        Console.WriteLine("Started, press ctrl + c to terminate.");

        _listeners.Add(Listen(cancelSource.Token));

        cancelSource.Token.WaitHandle.WaitOne();
        Task.WaitAll(_listeners.ToArray(), cancelSource.Token);
    }
}

public async Task Listen(CancellationToken token){
    var listener  = new TcpListener(IPAddress.Parse("0.0.0.0"), 9096);
    listener.Start();

    Console.WriteLine("Listening on port 9096");

    while (!token.IsCancellationRequested) {
        // Also tried putting AcceptTcpClientAsync here.
        await Task.Run(async () => {
            var client = await listener.AcceptTcpClientAsync();
            using (var stream = client.GetStream())
            using (var streamReader = new StreamReader(stream, Encoding.UTF8))
            using (var streamWriter = new StreamWriter(stream, Encoding.UTF8)) {
                while (!token.IsCancellationRequested) {    
                    // DO WORK WITH DATA RECEIVED
                    vat data = await streamReader.ReadAsync();
                    await streamWriter.WriteLineAsync("Request received.");
                }
            }
        });
    }

    Console.WriteLine("Stopped Accepting Requests.");
    listener.Server.Close();
    listener.Stop();
}

1 个答案:

答案 0 :(得分:0)

这实际上是按照您设计的方式工作的,但是您只能建立一个连接。我不会为您编写完整的套接字实现(因为这可能会相当深入)。但是,对于您的主要问题,您需要将AcceptTcpClientAsync放入循环中,否则将无法获得更多连接

var cancellation = new CancellationTokenSource();

...

var listener = new TcpListener(...);
listener.Start();
try
{
    while (!token.IsCancellationRequested)
    {
        var client = await  listener.AcceptTcpClientAsync()
        ...
    }
}
finally
{
    listener.Stop();
}

// somewhere in another thread
cancellation.Cancel();

更新

  

我尝试过,并且没有任何变化。还是不接   连接在第一个之后。

 await ...
 while (!token.IsCancellationRequested) {    
      // DO WORK WITH DATA RECEIVED

很明显,AcceptTcpClientAsync永远不会再被调用,因为您正在等待任务。这种方法可以接受客户端,如果您不能调用它,就不会再获得任何客户端。

您不能在这里阻止,这是您在做什么。请查看一些套接字服务器示例,以更好地了解如何编写侦听器