TCP服务器使用MAX CPU利用率

时间:2010-02-25 08:16:49

标签: c# tcp

我写这个TCP通信库。问题是。当客户端连接时。 CPU使用率增加到最大值......这会导致其他应用程序变慢...

请看一下代码并纠正我错误的地方..

我的TCP库的主要代码是

TCP服务器类

  public class TCPServerEndPoint : ICommunication
    {

        private string channelName;

        private string localIP;

        private int localPort;

        private string remoteIP;

        private int remotePort;

        private TcpListener tcpListenter;

        /// <summary>
        /// Accept the incomming connection and pass it to a thread to handle communication.
        /// </summary>
        private TCPServerWorker worker;

        /// <summary>
        /// List of threads created for connected clients.
        /// </summary>
        List<TCPServerWorker> workerThreads;

        /// <summary>
        /// Thread to keep listening process in seperate thread.
        /// </summary>
        private Thread serverThread;

        /// <summary>
        /// Flag to keep status of Endpoint.
        /// </summary>
        private bool keepRunning;

        public TCPServerEndPoint()
        {
            this.keepRunning = false;
            Guid guid = Guid.NewGuid();
            channelName = guid.ToString();
            workerThreads = new List<TCPServerWorker>();
        }

        public TCPServerEndPoint(string localIP, int localPort, string remoteIP, int remotePort)
        {
            this.localIP = localIP;
            this.localPort = localPort;
            this.remoteIP = remoteIP;
            this.remotePort = remotePort;

            workerThreads = new List<TCPServerWorker>();

            this.keepRunning = false;
        }        

        public event EventHandler<CommEventArgs> OnCommReceive;   


        public int CommStart()
        {
            if (this.IsStarted == true)
            {
                Console.WriteLine("TCP Server is already running");
                return -1;
            }

            serverThread = new Thread(new ThreadStart(StartListening));
            serverThread.IsBackground = true;
            serverThread.Start();

            return 0;
        }

        private void StartListening()
        {
            try
            {
                IPAddress localAddress = IPAddress.Parse(this.localIP);
                tcpListenter = new TcpListener(localAddress, this.localPort);
                tcpListenter.Start();
                Console.WriteLine("TCP Server started");
                Console.WriteLine("Server is listening on port : {0}", this.localPort);

                this.keepRunning = true;

                // look for incomming connections
                while (this.keepRunning)
                {
                    // connection received
                    TcpClient client = tcpListenter.AcceptTcpClient();

                    // create a new WorkerThread and pass the connected client to handle.
                    worker = new TCPServerWorker(client);
                    worker.dataReceived += new EventHandler<CommEventArgs>(worker_dataReceived);
                    workerThreads.Add(worker);
                    worker.Start();
                }

                tcpListenter.Stop();
                Console.WriteLine("TCP Server stopped");
                this.keepRunning = false;
            }
            catch
            {                
                return;
            }
        }

        void worker_dataReceived(object sender, CommEventArgs e)
        {
            if (this.OnCommReceive != null)
            {
                e.commChannel = this;
                this.OnCommReceive(this, e);
            }
        }


        public int CommStop()
        {
            if (this.IsStarted == false)
                return -1;

            // Close all worker threads created for connected clients.
            foreach (TCPServerWorker item in workerThreads)
            {
                item.KeepRunning = false;
            }

            // break the listening loop
            this.keepRunning = false;

            // clear the worker thread list
            workerThreads.Clear();

            // force server to receive message to break while(keepRunning) loop
            byte[] data = new byte[4];
            IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(this.localIP), localPort);
            Socket tcpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            tcpClient.Connect(ipEndPoint);
            tcpClient.SendTo(data, ipEndPoint);
            tcpClient.Close();

            return 0;
        }


        public int CommSend(CommEventArgs obj)
        {
            obj.destAddress = this.remoteIP;
            obj.destPort = this.remotePort;
            return CommSendTo(obj);
        }


        public int CommSendTo(CommEventArgs obj)
        {
            int n;
            byte[] buf;
            try
            {
                IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(obj.destAddress), obj.destPort);
                buf = (byte[])obj.data;

                Socket tcpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                tcpClient.Connect(ipEndPoint);
                n = tcpClient.SendTo(buf, ipEndPoint);
                tcpClient.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception :: {0}", ex.Message);
                return -1;
            }
            if (n == buf.Length)
            {
                if (OnCommSendComplete != null)
                {
                    OnCommSendComplete(this, obj);
                }              
                Console.WriteLine("Sent {0} bytes to {1}:{2}", n, obj.destAddress, obj.destPort);
            }
            else
            {               
                return -1;
            }

            return n;
        } 
    }
}

TCPServerWorker.cs

 class TCPServerWorker
    {

        private TcpClient client;


        private bool keepRunning;


        public event EventHandler<CommEventArgs> dataReceived;


        private const int MAX_TCP_DATA = 64000;


        public bool KeepRunning
        {
            get
            {
                return this.keepRunning;
            }
            set
            {
                this.keepRunning = value;
            }
        }

        public TCPServerWorker(TcpClient client)
        {
            this.client = client;
            this.keepRunning = false;
        }

        public void Start()
        {
            Thread thread = new Thread(new ThreadStart(Process));
            thread.IsBackground = true;
            thread.Start();
        }

        private void Process()
        {
            if (client.Connected == true)
            {
                Console.WriteLine("Client connected :: {0}", client.Client.RemoteEndPoint);
                this.keepRunning = true;

                while (this.keepRunning)
                {
// in my view. here is the main problem. this loop run for infinite time and causes CPU to reach at 100
                    byte[] buffer = new byte[MAX_TCP_DATA];                    
                    NetworkStream stream = client.GetStream();
                    StreamWriter writer = new StreamWriter(client.GetStream());

                    if (stream.DataAvailable == true)
                    {
                        int receivedBytesCount = stream.Read(buffer, 0, buffer.Length);

                        byte[] receivedBuffer = new byte[receivedBytesCount];

                        Array.Copy(buffer, receivedBuffer, receivedBytesCount);

                        String msg = Encoding.UTF8.GetString(receivedBuffer);
                        Console.WriteLine("Received MSG ::: " + msg);

                        writer.WriteLine("Server : Received {0} bytes", receivedBytesCount);

                        CommEventArgs comEventArg = new CommEventArgs();
                        comEventArg.data = (byte[])receivedBuffer;
                        IPEndPoint remoteIPEndPoint = (IPEndPoint)client.Client.RemoteEndPoint;

                        comEventArg.srcAddress = remoteIPEndPoint.Address.ToString();
                        comEventArg.srcPort = remoteIPEndPoint.Port;
                        comEventArg.length = receivedBytesCount;
                        this.OnDataReceived(comEventArg);

                        writer.Flush();
                    }
                }
                client.Close();                
            }
        }

        protected void OnDataReceived(CommEventArgs e)
        {
            if (this.dataReceived != null)
            {
                this.dataReceived(this, e);
            }
        }
    }
}

4 个答案:

答案 0 :(得分:1)

您正在使用非阻塞I / O,这会导致客户端(至少)循环

 while (this.keepRunning) {...}

通过忙碌等待消耗所有CPU资源。

您应该考虑使用阻塞I / O或Socket.Select

查看第一句话here

有关select

的详细信息

答案 1 :(得分:0)

有一点需要注意的是,你从未设置过IsStarted ..你只需要它._。也许你正在产生数百个线程= /我在谈论TCPServerEndPoint类= /

答案 2 :(得分:0)

是的,您正忙着等待连接。我不知道套接字编程所以我不能给你详细信息,但你需要做的是等待使用阻塞系统调用的连接。

答案 3 :(得分:0)

我在修改TCPServerWorker.cs的Process方法后解决了这个问题

这是更改

 private void Process()
        {
            if (client.Connected == true)
            {
                Console.WriteLine("Client connected :: {0}", client.Client.RemoteEndPoint);
                Byte[] bytes = new Byte[MAX_TCP_DATA];
                String data = null;
                NetworkStream stream = client.GetStream();

                int i;

                try
                {
                    // Loop to receive all the data sent by the client.
                    while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        // bytes contains received data in byte[].
                        // Translate data bytes to a UTF-8 string.
                        byte[] receivedBuffer = new byte[i];
                        Array.Copy(bytes, receivedBuffer, i);

                        data = System.Text.Encoding.UTF8.GetString(receivedBuffer);
                        Console.WriteLine("Received MSG ::: " + data);

                        // Process the data sent by the client.

                        byte[] msg = System.Text.Encoding.UTF8.GetBytes(data);

                        // Send back a response.
                        stream.Write(msg, 0, msg.Length);

                        CommEventArgs comEventArg = new CommEventArgs();
                        comEventArg.data = receivedBuffer;
                        IPEndPoint remoteIPEndPoint = (IPEndPoint)client.Client.RemoteEndPoint;
                        comEventArg.srcAddress = remoteIPEndPoint.Address.ToString();
                        comEventArg.srcPort = remoteIPEndPoint.Port;
                        comEventArg.length = i;
                        this.OnDataReceived(comEventArg);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception : " + ex.Message);
                }
                finally
                {
                    client.Close();
                }                  
            }
        }