TCP通訊之非同步實現
阿新 • • 發佈:2021-12-15
首先本內容是參考於別人的一篇文章,由於時間久遠沒找到原作者。今天寫本篇文章用於技術記錄,便於日後檢視。
服務端:
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); } } }