使用await和async的C#5.0异步TCP/IP服务器

4

我编写了以下Tcp服务器应用程序。问题是它不能同时执行单个客户端。也就是说,如果一个客户端连接,服务器将不接受其他客户端的连接。请帮我修复代码:

void Run()
{
    tcpListener.Start();           

    while (true)
    {
        Console.WriteLine("Waiting for a connection...");

        try
        { 
            var client = await tcpListener.AcceptTcpClientAsync();
            await Accept(client);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}

private async Task Accept(TcpClient client)
{
    //get client information 
    string clientEndPoint = GetClientIPAddress(client);            
    Console.WriteLine("Client connected at " + clientEndPoint);
    log.Info("Client connected at " + clientEndPoint);

    await Task.Yield (); 

    try 
    {              
        using (client) 
            using (NetworkStream stream = client.GetStream ()) 
            { 
                byte[] dataReceived = new byte [50];                  
                while (await stream.ReadAsync(dataReceived, 0, dataReceived.Length) != 0) //read input stream                
                {                    
                    //process data here                        
                    await ProcessData(dataReceived);                      
                }                   
            }
    } //end try
    catch (Exception ex) 
    {
        Console.WriteLine(ex.Message);                
        if (client.Connected)
            client.Close();
    }
} //end Accept(TcpClient client)

你是否尝试多次连接同一个端口? - maf748
1个回答

4
问题如下:
await Accept(client);

您正在等待 Accept 的结果,因此您无法接受新连接(因为在 Accept 处理过程中您没有执行 AcceptTcpClientAsync)。
以下是一个正确的示例: https://dev59.com/5WEi5IYBdhLWcg3wueN0#21018042

你应该将其更改为 async void Accept(client) {...},并在 Run 方法中正常调用它,而不使用 await 关键字。 - Laith
@Laith,我不是async void的狂热支持者。我更喜欢像链接中的答案中所做的那样跟踪待处理任务。 - noseratio - open to work
你是对的。如果你想跟踪所有正在运行的任务,你需要以某种方式保留对它们的引用。你的方法更好 :) - Laith
非常感谢!是的,将Accept调用中的await去掉,并将Accept返回值从Task改为void确实解决了问题。 - AM0
1
根据您的评论,我将任务添加回“接受”状态,并以以下方式调用它:var task = Accept(client)。 - AM0
@AM0,使用Task而不是async void的想法是为了方便错误处理并跟踪挂起的连接(在List<Task>中)。 - noseratio - open to work

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接