tags:

views:

110

answers:

4

hi. i write this TCP communication library. the problem is that. when a client connects. the CPU usages boosts to maximum....this causes other application to become slow...

please take a look at the code and correct me where i did wrong..

the main code of my TCP library is

TCP Server Class

  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);
            }
        }
    }
}
A: 

One thing to note is that you never SET IsStarted .. you only GET it ._. Maybe you're spawning hundreds of threads =/ I'm talking about the TCPServerEndPoint class =/

ItzWarty
i am getting value if keepRunning in IsStarted
Mohsan
Rephrase what you just stated, please. I'm not trying to be a grammar-police or anything, as I believe languages are for communication, not to act "smart"... but I wasn't able to understand what you said. Sorry if I sound like I'm trolling.
ItzWarty
you said that "you never SET IsStarted .. you only GET it" so in reply i said that. i am using the value of keepRunning (variable) in IsSrated.
Mohsan
A: 

Yes, you are busy waiting for a connection. I don't know socket programming so I can't give you details, but what you need to do is wait for a connection using the blocking system call.

Kevin Peterson
AcceptTcpClient blocks until a client comes in, so that shouldn't be the reason why his program is hogging the processor
ItzWarty
+1  A: 

You're using nonblocking I/O which leads to a loop (at least) in your client

 while (this.keepRunning) {...}

which is consuming all your CPU resources by busy waiting.

You should consider to use blocking I/O or Socket.Select

Look at the first remark here

Details about select

stacker
A: 

I solved the issue after modifying the Process method of TCPServerWorker.cs

here is the changes

 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();
                }                  
            }
        }
Mohsan