如何使用TCPListener更好地处理客户端?

时间:2010-07-23 05:28:35

标签: .net sockets tcplistener

我遇到了too many connections的问题经过一些测试我扣除了问题是我的服务器。服务器侦听端口位于左侧的事实应该告诉我。

当使用不同机器上的服务器运行相同的客户端代码时,我没有打开数百个端口。当我的本地机器上的服务器得到> 200连接连接到我的侦听端口。我想我正在处理错误的客户。我的代码在下面,删除了所有非服务器和客户端代码

{
    TcpListener server = null;
    server = new TcpListener(port);
    server.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
    server.Start();

    while (true)
    {
        var client = server.AcceptTcpClient();
        using(var stream = client.GetStream()) {
        ...
        stream.Read(...
        ...
        stream.Write(...
        } //using above should close this.
        client.Close();
    }
    server.Stop();
}

我修改了代码以使用异步连接,并且它第二次锁定了它。直接在while(client.Connected)

之下。
    server = new TcpListener(port);
    server.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
    server.Start();
    server.BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpClientCallback), server);
    while (true)
        Thread.Sleep(1000); //infinite loop for testing




public void DoAcceptTcpClientCallback(IAsyncResult ar)
{
    Byte[] bytes = new Byte[1024 * 4];
    TcpListener listener = (TcpListener)ar.AsyncState;
    using (TcpClient client = listener.EndAcceptTcpClient(ar))
    {
        using (var stream = client.GetStream())
        using (var ostream = new MemoryStream())
        {
            while (client.Connected)
            {
                int i;
                while ((i = stream.Read(bytes, 0, bytes.Length)) == bytes.Length)
                    ostream.Write(bytes, 0, i);

                ostream.Write(bytes, 0, i);
                szresults = Func(ostream)
                var obuf = Encoding.UTF8.GetBytes(szresults);
                stream.Write(obuf, 0, obuf.Length);
            }
        }
        client.Close();
    }
}

2 个答案:

答案 0 :(得分:2)

您正在处理同一线程中的连接。这意味着您一次只能主动处理单个连接。最简单的方法是将客户端传递给新线程,并在那里处理它。

现在不能很好地扩展 - 在任何地方使用完全异步操作将允许您使用更少的线程服务相同数量的客户端 - 但在大多数情况下,它将运行良好,IME。这肯定是我下次去的地方。

理想情况下,您不希望每次都创建一个新的OS线程 - 为此使用系统线程池可能是合理的,因此在完全处理连接后可以重用该线程。填补操作系统线程池存在风险,但我怀疑不太可能咬你。

最后,我将TcpClient放入using语句中,以确保即使其他内容失败也要处理它。当然,如果你把它交给另一个线程,它应该是那个立即使用using语句的线程。

答案 1 :(得分:0)

您需要为每个连接创建线程并使用socket.shutdown和s ocket.close方法正确关闭套接字,因为在您的代码中可以看到您没有关闭套接字并直接停止服务器到期哪个插座保持打开状态。

我希望您完成一次 article 。我得到了本文图5的帮助。

您可能还会在本文的here

文章中遇到一些相关问题