c#套接字处理多个客户端

时间:2011-04-21 10:08:37

标签: c# sockets tcp

我有以下代码,我想将其作为我的服务器实现。据我所知,它是异步的。并应允许来自多个客户的连接......

public void Start()
{          
    TcpListener listener = new TcpListener(IPAddress.Any, 10250);
    listener.Start();
    Console.WriteLine("Listening...");

    while (true)
    {
        IAsyncResult res = listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
        connectionWaitHandle.WaitOne();
    }
}

private void HandleAsyncConnection(IAsyncResult res)
{
    TcpListener listener = (TcpListener)res.AsyncState;
    TcpClient client = listener.EndAcceptTcpClient(res);
    connectionWaitHandle.Set();

    StringBuilder sb = new StringBuilder();
    var data = new byte[client.ReceiveBufferSize];

    using (NetworkStream ns = client.GetStream())
    {             
        // Test reply
        Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
        ns.Write(replyData, 0, replyData.Length);
        ns.Flush();
        ns.Close();
    }

    client.Close();
}

我有一个测试应用程序,它只是向我的服务器发出请求。正如您在代码中看到的那样,服务器只回复其日期/时间。测试应用程序发送20个请求,这些请求只是测试字符串。对于这些请求中的每一个,它都会打开一个套接字,将数据发送到我的服务器,然后再次关闭套接字。

这适用于运行一个测试应用程序。但是,如果我打开两个测试应用程序,则第二个无法连接到服务器。我想是因为我正在处理请求异步。并且因为我的测试应用程序打开然后在每次调用之前关闭套接字我可以处理来自多个客户端的请求吗?

2 个答案:

答案 0 :(得分:19)

修改

如果使用> =。Net4.5,最好使用新的网络方法,然后允许采用asyncawait。因此,最好按照this post中提供的示例作为起点。

原帖

以下代码演示了如何异步接受多个客户端,而无需为每个连接分离新线程。

private TcpListener listener;
public void Start()
{          
    listener = new TcpListener(IPAddress.Any, 10250);
    listener.Start();
    Console.WriteLine("Listening...");
    StartAccept();

}
private void StartAccept()
{
    listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
}
private void HandleAsyncConnection(IAsyncResult res)
{
    StartAccept(); //listen for new connections again
    TcpClient client = listener.EndAcceptTcpClient(res);
    //proceed

}

您可以将此模式用于大多数异步操作。

答案 1 :(得分:1)

与您使用AcceptTcpClient相比,您的方式没有任何好处。只需循环并为每个接受的连接创建一个新线程:

public void Start()
{          
    TcpListener listener = new TcpListener(IPAddress.Any, 10250);
    listener.Start();
    Console.WriteLine("Listening...");
    while (canRun)
    {
       var client = listener.AcceptTcpClient();
       new Thread(ClientThread).Start(client);
    }
}

private void ClientThread(IAsyncResult res)
{
    TcpClient client = (TcpClient)res.AsyncState;

    StringBuilder sb = new StringBuilder();
    var data = new byte[client.ReceiveBufferSize];

    using (NetworkStream ns = client.GetStream())
    {             
        // Test reply
        Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
        ns.Write(replyData, 0, replyData.Length);
        ns.Flush();
        ns.Close();
    }

    client.Close();
}

使用异步方法时的一个黄金法则是 NOT 阻止操作。阻止会破坏使用异步操作的目的。

public void Start()
{          
    TcpListener listener = new TcpListener(IPAddress.Any, 10250);
    listener.Start();
    Console.WriteLine("Listening...");
    listener.BeginAcceptTcpClient(OnAccept, listener);
}

private void OnAccept(IAsyncResult res)
{
    TcpListener listener = (TcpListener)res.AsyncState;
    TcpClient client = listener.EndAcceptTcpClient(res);

    StringBuilder sb = new StringBuilder();
    var data = new byte[client.ReceiveBufferSize];

    using (NetworkStream ns = client.GetStream())
    {             
        // Test reply
        Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
        ns.Write(replyData, 0, replyData.Length);
        ns.Flush();
        ns.Close();
    }

    client.Close();
}