在.net

时间:2015-08-09 12:07:14

标签: c# .net sockets networking tcp

我需要构建一个应用程序(服务器)来处理通过TCP从客户端发送的数据。我必须能够支持(至少)2000个连接。我已经尝试编写TCP服务器,但我发现当我开始达到600/700连接时,我服务器的响应速度很慢(随着接收越来越多的连接,它实际上会随着时间的推移而减慢)。我通常不会编写网络代码,所以我确信有很多概念我还没有完全理解,可以改进。

我的服务器的主要目的是:

  1. 处理从客户端发送的数据并将其存储在sql数据库中。
  2. 决定(基于 收到的最后一条消息)对客户的正确回应是什么。
  3. 排列回复列表 一次一个地发送给客户。
  4. 这需要为所有客户实现。以下是我实施的代码:

        private readonly TcpListener tcpListener;
        private readonly Thread listenThread;    
        private bool run = true;
    
        public Server()
        {
             this.tcpListener = new TcpListener(IPAddress.Any, AppSettings.ListeningPort); //8880 is default for me.
             this.listenThread = new Thread(new ThreadStart(ListenForClients));
             this.listenThread.Start();
        }
    
        private void ListenForClients()
        {
             this.tcpListener.Start();
    
             while (run) {
                  TcpClient client = this.tcpListener.AcceptTcpClient();
    
                  //create a thread to handle communication with connected client
                  Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
                  clientThread.Start(client);
              }
        }
        private void HandleClientComm(object client)
        {
            Queue responseMessages = new Queue();
            while (run)
            {
                try
                {
                    lastMessage = clientStream.GetMessage();
    
                    if (lastMessage.Length > 0)
                    {
                        // Process logic here...  
                        //an item may be added to the response queue, depending on logic.
                    }
    
                    if (responseMessages.Count > 0)
                    {
                       clientStream.WriteMessage(msg);
                       clientStream.Flush();
    
                       // sleep for 250 milliseconds (or whats in the config).
                       Thread.Sleep(AppSettings.MessageSendDelayMilliseconds); 
                    }
                }
                catch (Exception ex)
                {
                    break;
                }
            }
            tcpClient.Close();
        }
    

    最后,这是我写的一个扩展课来帮助我:

    namespace System.Net.Sockets
    {
        using System.Text;
    
        public static class NetworkSteamExtension
        {
            private static readonly ASCIIEncoding Encoder = new ASCIIEncoding();
    
            public static string GetMessage(this NetworkStream clientStream)
            {
                string message = string.Empty;
                try
                {
                    byte[] bMessage = new byte[4068];
                    int bytesRead = 0;
                    while (clientStream.DataAvailable)
                    {
                        bytesRead = clientStream.Read(bMessage, 0, 4068);
                        message += Encoder.GetString(bMessage, 0, bytesRead);
                    }
                }
                catch (Exception)
                {
    
                }
                return message;         
            }
    
            public static void WriteMessage(this NetworkStream clientStream, string message)
            {
                byte[] buffer = Encoder.GetBytes(message);
                clientStream.Write(buffer, 0, buffer.Length);
                clientStream.Flush();
            }
        }
    }
    

    关于这个主题的很多文章人们正在使用套接字。我还读到.net 4.5 async / await是实现解决方案的最佳方式。

    我想确保我利用.net中的最新功能(如果它有帮助,甚至4.5.2)并构建一个可以处理至少2000个连接的服务器。有人可以建议吗?

    非常感谢!

1 个答案:

答案 0 :(得分:2)

好的,我们需要修复一些API使用错误,然后解决创建太多线程的主要问题。众所周知,许多连接只能通过异步IO有效处理。数百个连接被视为“太多”。

您的客户端处理循环必须是异步的。重写HandleClientComm以便它使用异步套接字IO。这很容易等待。您需要在网上搜索“.net socket await”。

您可以继续使用同步接听电话。那里没有缺点。保留简单的同步代码。只允许那些具有重要avgWaitTime * countPerSecond产品的调用异步。这通常是所有套接字调用。

您假设DataAvailable返回任何给定消息中的字节数。 TCP不保留消息边界。你需要自己做。 DataAvailable值几乎没有意义,因为它可能会低估将来到达的真实数据。

通常使用更高级别的序列化协议会更好。例如,带有长度前缀的protobuf。不要使用ASCII。您可能只是因为您不知道如何使用“真实”编码来完成此操作。

使用using处理所有资源。不要使用非泛型Queue类。不要刷新流,这对套接字没有任何作用。

你为什么睡觉?