北京又在打雷下大雨了,學習Unity以來,越來越感興趣,情不自禁的想要學習更多知識
這次自己搭建一個Socket模塊,比較基礎,適合新手學習,詳細介紹Socket的搭建過程,同樣會把詳細過程在代碼里進行注釋~
在搭建Socket過程中,需要創建以下幾個常用的方法:
1.創建套接字(socket)
2.綁定Ip和端口
3.監聽方法
4.接收客戶端請求的方法
5.收發消息的方法
創建SocketManger管理類
把客戶端與服務端代碼都寫在新建的SocketManger里,並把SocketManger寫成單例,方便調用
using System.Net; //引入套接字協議類 using System.Net.Sockets; using System; using System.Text; public class SocketManager { #region 單例類 private static SocketManager instance; private SocketManager() { } public static SocketManager Instance { get { if (instance == null) { instance = new SocketManager(); } return instance; } } #endregion public delegate void MyCallBack(string msg); //聲明一個委托類型,在服務器和客戶端工作的時候,會使用這個回調方法反饋當前交互的具體情況
服務端代碼
#region 服務器代碼 /* 創建服務器 * 等待客戶端的連接 * 接受消息 */ Socket serverSocket; //創建服務器的套接字對象 MyCallBack serverCallBack; //定義一個服務器使用的回調委托對象 byte[] serverBuffer; //數據緩存區 文字,音頻,視頻,圖片... public void InitServer(MyCallBack callBack) { serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //參數(1.使用IP地址的類型 2.套接字類型,使用TCP的流式傳輸 3.使用TCP協議) serverBuffer = new byte[1024]; //初始化緩沖區的大小 serverCallBack = callBack; //綁定初始化服務器的回調方法 IPEndPoint point = new IPEndPoint(IPAddress.Any, 34567); //參數(1.地址,代表一台電腦, 2.端口號表示一個應用) serverSocket.Bind(point); //綁定地址節點 serverSocket.Listen(10); //開始監聽, 一旦監聽成功,服務器就啟動,10代表最大監聽數量 serverCallBack("服務器啟動成功"); //服務器開始進入等待用戶連接的狀態 //開辟一條子線程實時監測是否有人連接 //一旦有客戶端連接,立馬通知主線程,通知內容會以IAsyncResult 返回,連接者的所有信息 serverSocket.BeginAccept(ServerAccept, serverSocket); } //服務器開始接收的方法 void ServerAccept(IAsyncResult ar) { serverSocket = ar.AsyncState as Socket; //拿到當前連接服務器的Socket 對象 Socket workingSocket = serverSocket.EndAccept(ar); //將當前的Socket的全部信息交給一個新的Socket處理 workingSocket.BeginReceive(serverBuffer, 0, serverBuffer.Length, SocketFlags.None,ServerReceive, workingSocket); //(數據收發緩存區,起始位置,長度,不分類型,全部接收, 接受消息之后的回調,當前Socket的狀態) serverSocket.BeginAccept(ServerAccept, serverSocket); //尾遞歸 } //服務器接收消息之后的回調方法 void ServerReceive(IAsyncResult ar) { Socket workingSorket = ar.AsyncState as Socket; int size=workingSorket.EndReceive(ar); //拿到接收到的數據一共有多少字節 string str = Encoding.UTF8.GetString(serverBuffer); //將接收到的byte數組轉換成字符串 serverCallBack("接收到了" + size + "字節"); serverCallBack(str); workingSorket.BeginReceive(serverBuffer, 0, serverBuffer.Length, SocketFlags.None, ServerReceive, workingSorket); //尾遞歸 } #endregion
客戶端代碼
#region Socket clientSocket; MyCallBack clientCallBack; byte[] clientBuffer; //客戶端連接服務器的方法 public void ClientConnectServer(string ip,int port,MyCallBack callBack) { clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); clientBuffer = new byte[1024]; clientCallBack = callBack; clientSocket.Connect(IPAddress.Parse(ip),port); //連接服務器 clientCallBack("連接服務器成功"); clientSocket.BeginReceive(clientBuffer, 0, clientBuffer.Length, SocketFlags.None,ClientReceive, clientSocket); } void ClientReceive(IAsyncResult ar) { Socket WorkingSocket = ar.AsyncState as Socket; int size=WorkingSocket.EndReceive(ar); //接收多少字節 string msg= Encoding.UTF8.GetString(clientBuffer); clientCallBack("接收了"+size+"字節"); clientCallBack(msg); clientSocket.BeginReceive(clientBuffer, size, clientBuffer.Length, SocketFlags.None, ClientReceive, WorkingSocket); } //客戶端發送消息的方法 public void ClientSendMsg(string msg) { byte[] buffer= Encoding.UTF8.GetBytes(msg); clientSocket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, SendCallBack, clientSocket); } void SendCallBack(IAsyncResult ar) { Socket workingSocket = ar.AsyncState as Socket; workingSocket.EndSend(ar); clientCallBack("發送完成"); } #endregion
簡單的Socket搭建完成,但是有一點小Bug,服務器進入等待用戶連接狀態后,會開辟子線程實時檢測,沒有關閉這條線程,因此在搭建服務器的腳本,可以在Start方法里寫一個方法,在程序退出時關閉這條線程! 這個方法在關閉程序時自動調用
private void OnApplicationQuit() { serverSocket.Shutdown(SocketShutdown.Both); serverSocket.Close(); }
簡單的Socket搭建完了,當然這只是非常基礎的Socket傳遞,在實際使用中,還要考慮很多問題,比如Socket的沾包, 閉包,需要進一步處理