接受TCP客户端异步

时间:2014-03-05 06:44:38

标签: c# tcp tcpclient tcplistener

我一直在制作服务器。我在async方法中使用TcpListener.AcceptTcpClientAsync(),但我不知道如何实际使其工作。我现在的代码是:

private static async void StartServer()
{
    Console.WriteLine("S: Server started on port {0}", WebVars.ServerPort);
    var listener = new TcpListener(WebVars.LocalIp, WebVars.ServerPort);
    listener.Start();
    var client = await listener.AcceptTcpClientAsync();
}

如何处理客户端?我只是继续编码,它会自动创建相同方法的新线程,还是我需要做一些魔术方法来为我做?

编辑:当前代码:

private static Task HandleClientAsync(TcpClient client)
{
    var stream = client.GetStream();
    // do stuff
}
/// <summary>
/// Method to be used on seperate thread.
/// </summary>
private static async void RunServerAsync()
{
    while (true)
    {
        Console.WriteLine("S: Server started on port {0}", WebVars.ServerPort);
        var listener = new TcpListener(WebVars.LocalIp, WebVars.ServerPort);
        listener.Start();
        var client = await listener.AcceptTcpClientAsync();
        await HandleClientAsync(client);
    }
}

2 个答案:

答案 0 :(得分:5)

魔法为你创建专用线程没有什么,尽管有一些线程用于IO完成,可以发挥作用,特别是如果你没有同步您需要返回的上下文。

您应该决定是否希望StartServer方法在接受单个连接时实际完成,或者在您被告知关闭之前保持循环。

无论哪种方式,您显然都需要决定如何处理客户端。您可以启动新线程并使用同步方法,也可以使用异步IO来处理同一线程中的所有内容。例如,要将传入数据转储到文件:

private Task HandleClientAsync(TcpClient client)
{
    // Note: this uses a *synchronous* call to create the file; not ideal.
    using (var output = File.Create("client.data"))
    {
        using (var input = client.GetStream())
        {
            // Could use CopyToAsync... this is just demo code really.

            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = await input.ReadAsync(buffer, 0, buffer.Length)) > 0)
            {
                await output.WriteAsync(buffer, 0, bytesRead);
            }
        }
    }
}

(假设客户端只是在完成数据写入时终止连接。)除了File.Create调用之外,这都是异步的 - 因此不需要为它创建单独的线程。

这只是一个例子,当然 - 真正的连接处理通常会更复杂。如果您的实际处理需要更多计算密集型,那么您可能需要考虑使用Task.Run来使用线程池......这样就不会干扰接受更多连接。

答案 1 :(得分:0)

//简而言之,所有功劳都应归功于c#7.0(Joseph Albahari和Ben Albahari)

    async void RunServerAsync()
    {
        var listner = new TcpListener(IPAddress.Any, 9999);
        listner.Start();
        try
        {
            while (true)
                await Accept(await listner.AcceptTcpClientAsync());
        }
        finally { listner.Stop(); }
    }


    const int packet_length = 2;  // user defined packet length

    async Task Accept(TcpClient client)
    {
        await Task.Yield();
        try
        {
            using(client)
            using(NetworkStream n = client.GetStream())
            {
                byte[] data = new byte[packet_length];
                int bytesRead = 0;
                int chunkSize = 1;

                while (bytesRead < data.Length && chunkSize > 0)
                    bytesRead += chunkSize = 
                        await n.ReadAsync(data, bytesRead, data.Length - bytesRead);

                // get data
                string str = Encoding.Default.GetString(data);
                Console.WriteLine("[server] received : {0}", str);

                // To do
                // ...

                // send the result to client
                string send_str = "server_send_test";
                byte[] send_data = Encoding.ASCII.GetBytes(send_str);
                await n.WriteAsync(send_data, 0, send_data.Length);

            }
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }