【问题标题】:Infinity while loop gets only one result无限while循环只得到一个结果
【发布时间】:2020-04-28 14:29:53
【问题描述】:

我正在编写一个 P2P 程序,它必须在它的多个实例之间发送和接收数据。 当我创建单独的线程以在无限循环中侦听传入数据时遇到问题,但我只收到第一条消息,然后没有其他消息。 我究竟做错了什么? 代码:

Task t = new Task(() => {
                try {
                    server = new TcpListener(IPAddress.Parse(STD_IP), STD_PORT);
                    server.Start();
                    odjemalec = server.AcceptTcpClient();
                    nwStream = odjemalec.GetStream();
                }
                catch (Exception ex) {
                    Console.WriteLine("Error\n" + ex.Message + "\n" + ex.StackTrace);
                }
                while(true) {
                    listen();
                }


            });
            t.Start();

标签: c# multithreading tcp


【解决方案1】:

如果你想使用任务(我强烈推荐这种方法),你需要一个Listener Task和一个TcpClient Responder Task用于每个传入的连接。

这是一个基本的 TCP 侦听器任务

static async Task StartTcpServerAsync()
{
    var tcpListener = new TcpListener(new IPEndPoint(IPAddress.Any, 9999));
    tcpListener.Start();
    while (true)
    {
        var tcpClient = await tcpListener.AcceptTcpClientAsync();
        _ = StartTcpClientAsync(tcpClient);
    }
}

我们初始化TcpListener 并开始监听连接。每次获得连接时,我们都会将关联的TcpClient 交给一个新任务。

这是一个服务器端 TCP 客户端任务 - 它位于服务器上,由侦听器启动

static async Task StartTcpClientAsync(TcpClient tcpClient)
{
    Console.WriteLine($"Connection from: [{tcpClient.Client.RemoteEndPoint}]");

    var stream = tcpClient.GetStream();
    var buffer = new byte[1024];

    while (true)
    {
        int x = await stream.ReadAsync(buffer, 0, 1024);
        Console.WriteLine($"[{tcpClient.Client.RemoteEndPoint}] _ " +
            $"read {x} bytes {System.Text.Encoding.UTF8.GetString(buffer)}");
    }
}

在这个例子中,我们只是写出接收到的字节。

终于

为了完整起见,这里有一个 Main 和一个 TCPSender - 通常 Sender 将位于完全不同的计算机上,但为了展示 Tasks 的强大功能,我们将从同一个进程运行它。

static async Task Main(string[] args)
{
    _ = StartTcpServerAsync();
    await Task.Delay(2000);
    await RunSenderAsync();
}
static async Task RunSenderAsync()
{
    var tcpClient = new TcpClient("127.0.0.1", 9999);
    var s = tcpClient.GetStream();
    tcpClient.NoDelay = true;
    for (var i = 65; i < 91; i++)
    {
        s.Write(BitConverter.GetBytes(i), 0, 1);
        await Task.Delay(1000);
    }
}

我发现很多人感到困惑的一个地方是,您需要在服务器上为收到的每个连接设置一个 TcpClient。

【讨论】:

  • 这将不起作用,因为您没有等待StartTcpClientAsync,所以也没有等待stream.ReadAsync
  • stream.ReadAsync 不创建线程......它适用于系统中断并且没有等待它不工作......它与Task.Run不同......同样System.Text.Encoding.UTF8.GetString(buffer)是错误的...... . 应该是System.Text.Encoding.UTF8.GetString(buffer, 0, x)
  • 嗨@Selvin StartTcpClientAsync 没有等待。如果等待它,那么在“StartTcpClientAsync”完成之前,我们永远不会看到任何新连接,这只会在第一个客户端断开连接时发生。因为这是从控制台应用程序运行的,所以没有同步上下文。
  • 我已经检查过(复制代码并编译)......它不起作用 - 它只按预期接受并且不读取(也按预期)
  • 修复方法是将_ = StartTcpClientAsync(tcpClient);替换为Task.Run(async () =&gt; await _ = StartTcpClientAsync(tcpClient));
猜你喜欢
  • 2011-09-26
  • 1970-01-01
  • 2012-11-15
  • 1970-01-01
  • 2021-09-24
  • 2013-10-27
  • 2014-07-17
  • 2013-11-28
  • 2012-04-14
相关资源
最近更新 更多