歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

C#中Socket服務端代碼分享

最近在對項目中Socket通訊中的服務端代碼進行優化,保證能接受盡可能多的客戶端的連接,並且不會丟掉連接,不會掉數據包。經過一段時間的反復測試和修改,終於達到了這一要求。服務端代碼采用了異步通訊的方式,並使用ManualResetEvent來對線程進行控制。在程序中,ManualResetEvent 的使用很關鍵。 ManualResetEvent 允許線程通過發信號互相通信。通常,此通信涉及一個線程在其他線程進行之前必須完成的任務。當一個線程開始一個活動(此活動必須完成後,其他線程才能開始)時,它調用 Reset 以將 ManualResetEvent 置於非終止狀態,此線程可被視為控制 ManualResetEvent。調用 ManualResetEvent 上的 WaitOne 的線程將阻止,並等待信號。當控制線程完成活動時,它調用 Set 以發出等待線程可以繼續進行的信號。並釋放所有等待線程。一旦它被終止,ManualResetEvent 將保持終止狀態(即對 WaitOne 的調用的線程將立即返回,並不阻塞),直到它被手動重置。可以通過將布爾值傳遞給構造函數來控制 ManualResetEvent 的初始狀態,如果初始狀態處於終止狀態,為 true;否則為 false。現在貼出主要的代碼,歡迎大家指正,代碼如下所示:

void ButtonStartListenClick(object sender, System.EventArgs e)
        {
            try
            {
                // Check the port value
                if(textBoxPort.Text == "")
                {
                    MessageBox.Show("Please enter a Port Number");
                    return;
                }
                if (txtConnectNum.Text.Trim() != "")
                {
                    iConnectNum = int.Parse(txtConnectNum.Text.Trim());
                    Flage = 0;
                }
                else
                {
                    MessageBox.Show("Please enter a Connect Number");
                    return;
                }

                string portStr = textBoxPort.Text;
                int port = System.Convert.ToInt32(portStr);
                // Create the listening socket...
                m_mainSocket = new Socket(AddressFamily.InterNetwork,
                    SocketType.Stream,
                    ProtocolType.Tcp);
                IPEndPoint ipLocal = new IPEndPoint (IPAddress.Any, port);
                // Bind to local IP Address...
                m_mainSocket.Bind( ipLocal );
                // Start listening...
                m_mainSocket.Listen(10000);
                // Set the event to nonsignaled state.設置無信號狀態的事件
                allDone.Reset();
                // Create the call back for any client connections...
                m_mainSocket.BeginAccept(new AsyncCallback (OnClientConnect), null);
                // Wait until a connection is made before continuing.等待連接創建後繼續
                allDone.WaitOne();
                
                UpdateControls(true);
                
            }
            catch(SocketException se)
            {
                MessageBox.Show ( se.Message );
            }

        }


// This is the call back function, which will be invoked when a client is connected
        public void OnClientConnect(IAsyncResult asyn)
        {
            try
            {
                //讓它繼續處理並建立與客戶端的連接
                allDone.Set();

                // Here we complete/end the BeginAccept() asynchronous call
                // by calling EndAccept() - which returns the reference to
                // a new Socket object
                Socket workerSocket = m_mainSocket.EndAccept (asyn);

                // Now increment the client count for this client
                // in a thread safe manner
                Interlocked.Increment(ref m_clientCount);

                if (m_clientCount == 1)
                {
                    lock (this)
                    {
                        stopwatch.Start();
                        dtStart = DateTime.Now;
                        writeLog("Server Start Socket Connect Time"+dtStart.ToString("yyyy-MM-dd HH:mm:ss fff"));
                    }
                }
                
                // Add the workerSocket reference to our ArrayList
                m_workerSocketList.Add(workerSocket);

                // Send a welcome message to client
                string msg = "Welcome client " + m_clientCount + "\n";
                SendMsgToClient(msg, m_clientCount);

                // Update the list box showing the list of clients (thread safe call)
                UpdateClientListControl();

                // Let the worker Socket do the further processing for the
                // just connected client
                WaitForData(workerSocket, m_clientCount);
                            
                // Since the main Socket is now free, it can go back and wait for
                // other clients who are attempting to connect
                m_mainSocket.BeginAccept(new AsyncCallback ( OnClientConnect ),null);
                // Wait until a connection is made before continuing.等待連接創建後繼續
                allDone.WaitOne();
            }
            catch(ObjectDisposedException)
            {
                System.Diagnostics.Debugger.Log(0,"1","\n OnClientConnection: Socket has been closed\n");
            }
            catch(SocketException se)
            {
                MessageBox.Show ( se.Message );
            }
            
        }


public class SocketPacket
        {
            // Constructor which takes a Socket and a client number
            public SocketPacket(System.Net.Sockets.Socket socket, int clientNumber)
            {
                m_currentSocket = socket;
                m_clientNumber  = clientNumber;
            }
            public System.Net.Sockets.Socket m_currentSocket;
            public int m_clientNumber;
            // Buffer to store the data sent by the client
            public byte[] dataBuffer = new byte[1024];
        }
        // Start waiting for data from the client
        public void WaitForData(System.Net.Sockets.Socket soc, int clientNumber)
        {
            try
            {
                if  ( pfnWorkerCallBack == null )
                {        
                    // Specify the call back function which is to be
                    // invoked when there is any write activity by the
                    // connected client
                    pfnWorkerCallBack = new AsyncCallback (OnDataReceived);
                }
                SocketPacket theSocPkt = new SocketPacket (soc, clientNumber);
                //receiveDone.Reset();
                soc.BeginReceive (theSocPkt.dataBuffer, 0,
                    theSocPkt.dataBuffer.Length,
                    SocketFlags.None,
                    pfnWorkerCallBack,
                    theSocPkt);
                //receiveDone.WaitOne();
            }
            catch(SocketException se)
            {
                MessageBox.Show (se.Message );
            }
        }
        // This the call back function which will be invoked when the socket
        // detects any client writing of data on the stream
        public  void OnDataReceived(IAsyncResult asyn)
        {
            SocketPacket socketData = (SocketPacket)asyn.AsyncState ;
            try
            {
                // Complete the BeginReceive() asynchronous call by EndReceive() method
                // which will return the number of characters written to the stream
                // by the client
                //receiveDone.Set();
                int iRx  = socketData.m_currentSocket.EndReceive (asyn);
                char[] chars = new char[iRx +  1];
                // Extract the characters as a buffer
                System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
                int charLen = d.GetChars(socketData.dataBuffer,
                    0, iRx, chars, 0);

                System.String szData = new System.String(chars);
                string msg = "" + socketData.m_clientNumber + ":";
                AppendToRichEditControl(msg + szData);
                //writeFromClientsMsgLog(msg + szData);

                // Send back the reply to the client
                string replyMsg = "Server Reply:" + szData.ToUpper();
                // Convert the reply to byte array
                byte[] byData = System.Text.Encoding.ASCII.GetBytes(replyMsg);

                Socket workerSocket = (Socket)socketData.m_currentSocket;
                workerSocket.Send(byData);


                if (m_clientCount == iConnectNum && Flage == 0)
                {
                    Interlocked.Increment(ref Flage);
                    string msgTime = "Server End Socket Action Time:";
                    lock(this)
                    {
                        stopwatch.Stop();
                        //lblTime.Text = stopwatch.Elapsed.Seconds.ToString();
                        int itime = stopwatch.Elapsed.Milliseconds;
                        
                        //msgTime += stopwatch.Elapsed.Seconds.ToString()+"--"+itime.ToString();
                        msgTime += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff");
                    }
                    writeLog(msgTime);

                    writeClientConnectionLog();
                    
                    //UpdateLabelTime(msgTime);
                    //byData = System.Text.Encoding.ASCII.GetBytes(msgTime);
                    //workerSocket.Send(byData);
                }
    
                // Continue the waiting for data on the Socket
                WaitForData(socketData.m_currentSocket, socketData.m_clientNumber );

            }
            catch (ObjectDisposedException )
            {
                System.Diagnostics.Debugger.Log(0,"1","\nOnDataReceived: Socket has been closed\n");
            }
            catch(SocketException se)
            {
                if(se.ErrorCode == 10054) // Error code for Connection reset by peer
                {    
                    string msg = "Client " + socketData.m_clientNumber + " Disconnected" + "\n";
                    AppendToRichEditControl(msg);
                    //writeFromClientsMsgLog(msg);

                    // Remove the reference to the worker socket of the closed client
                    // so that this object will get garbage collected
                    m_workerSocketList[socketData.m_clientNumber - 1] = null;
                    UpdateClientListControl();
                }
                else
                {
                    MessageBox.Show (se.Message );
                }
            }
        }


void CloseSockets()
        {
            if(m_mainSocket != null)
            {
                m_mainSocket.Close();
            }
            Socket workerSocket = null;
            for(int i = 0; i < m_workerSocketList.Count; i++)
            {
                workerSocket = (Socket)m_workerSocketList[i];
                if(workerSocket != null)
                {
                    workerSocket.Close();
                    workerSocket = null;
                }
            }    
        }

void SendMsgToClient(string msg, int clientNumber)
        {
            // Convert the reply to byte array
            byte[] byData = System.Text.Encoding.ASCII.GetBytes(msg);

            Socket workerSocket = (Socket)m_workerSocketList[clientNumber - 1];
            //workerSocket.Send(byData);
            workerSocket.BeginSend(byData, 0, byData.Length, 0,
                new AsyncCallback(SendCallback), workerSocket);
        }

        private void SendCallback(IAsyncResult asyn)
        {
            Socket client = (Socket)asyn.AsyncState;
            // 完成數據發送.  
            int bytesSent = client.EndSend(asyn);  
        }

完整的代碼下載

免費下載地址在 http://linux.linuxidc.com/

用戶名與密碼都是www.linuxidc.com

具體下載目錄在 /2012年資料/1月/15/C#中Socket服務端代碼分享/

Copyright © Linux教程網 All Rights Reserved