1. 程式人生 > 其它 >TCP通訊之非同步實現

TCP通訊之非同步實現

首先本內容是參考於別人的一篇文章,由於時間久遠沒找到原作者。今天寫本篇文章用於技術記錄,便於日後檢視。

服務端:

public class TCPServer
    {
        static byte[] buffer = new byte[1024];
        private static int count = 0;
        public static Socket socket = null;
        public static Socket socketClient = null;

        /// <summary>
        /// 客服端
        
/// </summary> public static Socket client = null; /// <summary> /// 啟動監聽 /// </summary> public static void Start(string ip, string port) { try { #region 啟動程式 //①建立一個新的Socket,這裡我們使用最常用的基於TCP的Stream Socket(流式套接字)
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //string ip = OperIni.ReadIni("BJIP", "key", "", Program.MainForm.iniFilePath); //string port = OperIni.ReadIni("BJPORT", "key", "", Program.MainForm.iniFilePath);
//②將該socket繫結到主機上面的某個埠 //方法參考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.bind.aspx socket.Bind(new IPEndPoint(IPAddress.Parse(ip), Int32.Parse(port))); //③啟動監聽,並且設定一個最大的佇列長度 //方法參考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.listen(v=VS.100).aspx socket.Listen(10000); //④開始接受客戶端連線請求 //方法參考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.beginaccept.aspx socket.BeginAccept(new AsyncCallback(ClientAccepted), socket); #endregion } catch (Exception err) { // MessageBox.Show("伺服器監聽開啟失敗:" + err.Message, "系統提示", MessageBoxButtons.OK, MessageBoxIcon.Error); } } #region 客戶端連線成功 /// <summary> /// 客戶端連線成功 /// </summary> /// <param name="ar"></param> public static void ClientAccepted(IAsyncResult ar) { #region //設定計數器 count++; // var socket = ar.AsyncState as Socket; //這就是客戶端的Socket例項,我們後續可以將其儲存起來 client = socket.EndAccept(ar); //客戶端IP地址和埠資訊 IPEndPoint clientipe = (IPEndPoint)client.RemoteEndPoint; //WriteLine(clientipe + " is connected,total connects " + count, ConsoleColor.Yellow); //接收客戶端的訊息(這個和在客戶端實現的方式是一樣的)非同步 client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), client); //準備接受下一個客戶端請求(非同步) socket.BeginAccept(new AsyncCallback(ClientAccepted), socket); #endregion } #endregion #region 接收和傳送客戶端的資訊 /// <summary> /// 接收某一個客戶端的訊息 /// </summary> /// <param name="ar"></param> public static void ReceiveMessage(IAsyncResult ar) { int length = 0; string message = ""; //收到到的訊息 socketClient = ar.AsyncState as Socket; //客戶端IP地址和埠資訊 IPEndPoint clientipe = (IPEndPoint)socketClient.RemoteEndPoint; try { #region //方法參考:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.endreceive.aspx length = socketClient.EndReceive(ar); if (length == 0) { throw new Exception("客戶端斷開"); } //讀取出來訊息內容 //ASCIIEncoding ASC = new ASCIIEncoding(); //message = ASC.GetString(buffer, 0, length); message = Encoding.Default.GetString(buffer); //輸出接收資訊 WriteLine(clientipe + "" + message, ConsoleColor.White); //接收下一個訊息(因為這是一個遞迴的呼叫,所以這樣就可以一直接收訊息)非同步 socketClient.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), socketClient); #endregion } catch (Exception ex) { //設定計數器 count--; //斷開連線 //WriteLine(clientipe + " is disconnected,total connects " + (count), ConsoleColor.Red); } } /// <summary> /// 傳送客戶端訊息 /// </summary> public static void Send(string send) { try { byte[] reply = Encoding.GetEncoding("GB2312").GetBytes(send); client.Send(reply); } catch (Exception err) { // MessageBox.Show("與主控通訊失敗!" + err.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } } #endregion #region 擴充套件方法 public static void WriteLine(string str, ConsoleColor color) { Console.ForegroundColor = color; Console.WriteLine("[{0}] {1}", DateTime.Now.ToString("MM-dd HH:mm:ss"), str); } /// <summary> /// 校驗和 /// </summary> /// <param name="msg"></param> /// <returns></returns> public static byte SumMake(byte[] msg) { byte b = 0; for (int i = 1; i < msg.Length - 2; i++) { b += msg[i]; } return b; } #endregion }

客戶端:

 class TCPClient
    {
        private Socket clientSocket;
        private byte[] receiveBuff;

        public TCPClient()
        {
            receiveBuff = new byte[1024];
        }

        /// <summary>
        /// 開啟連線
        /// </summary>
        /// <returns></returns>
        public bool connect(string ip, int port)
        {
            try
            {
                if (clientSocket == null || clientSocket.Connected == false)
                {
                    clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//初始化套接字
                }

                IPEndPoint remotepoint = new IPEndPoint(IPAddress.Parse(ip), port);//根據ip地址和埠號建立遠端終結點
                EndPoint end = (EndPoint)remotepoint;
                clientSocket.BeginConnect(end, new AsyncCallback(ConnectedCallback), clientSocket); //呼叫回撥函式

                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine("裝置連線失敗:" + ex.Message);
                return false;
            }
        }

        private void ConnectedCallback(IAsyncResult ar)
        {
            try
            {
                Socket client = (Socket)ar.AsyncState;
                client.EndConnect(ar);
                clientSocket.BeginReceive(receiveBuff, 0, receiveBuff.Length, 0, new AsyncCallback(ReceiveCallback), clientSocket);
                Console.WriteLine("裝置連線成功:" + client.RemoteEndPoint);
            }
            catch (Exception e)
            {
                Console.WriteLine("裝置連線失敗:" + e.Message);
            }
        }

        private void ReceiveCallback(IAsyncResult ar)
        {
            try
            {
                String content = String.Empty;

                // Retrieve the state object and the handler socket
                // from the asynchronous state object.

                Socket handler = (Socket)ar.AsyncState;//獲取控制代碼

                // Read data from the client socket. 
                int bytesRead = handler.EndReceive(ar);
                IPEndPoint remotepoint = (IPEndPoint)handler.RemoteEndPoint;//獲取遠端的埠

                if (bytesRead > 0)
                {
                    //處理收到的資訊
                    DealReceive(receiveBuff, bytesRead);

                    //處理完之後清空receive_buff
                    clearReceiveBuff();

                    clientSocket.BeginReceive(receiveBuff, 0, receiveBuff.Length, 0, new AsyncCallback(ReceiveCallback), handler);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                clearReceiveBuff();
            }
        }

        private void SendCallback(IAsyncResult ar) //傳送的回撥函式
        {
            Socket client = (Socket)ar.AsyncState;
            int bytesSend = client.EndSend(ar); //完成傳送
        }

        private void DealReceive(Byte[] receiveByte, int len)
        {
            byte[] temp = new byte[len];
            Array.Copy(receiveByte, 0, temp, 0, len);

            //string strReceive = StringConvert.byteToHexStr(temp);
            string strReceive = Encoding.Default.GetString(temp);

            Console.WriteLine(strReceive);
        }

        private void clearReceiveBuff()
        {
            Array.Clear(receiveBuff, 0, 1024);
        }

        public void sendToServer(byte[] byteData)
        {
            try
            {
                if (clientSocket != null && clientSocket.Connected)
                {
                    clientSocket.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), clientSocket);
                }
            }
            catch (SocketException ex)
            {
                Console.WriteLine("TCP傳送失敗:" + ex.Message);
            }
        }

    }