Socket之間的通信可以類比生活中打電話的案例。任何用戶在通話之前,首先要占有一部電話機,相當於申請一個Socket,同時要知道對方的號碼,相當於對方有一個固定的Socket,然后向對方撥號呼叫,相當於發出連接請求。假如對方在場並空閑,拿起 電話話筒,雙方就可以進行通話了。雙方的通話過程,是一方向電話機發出信號和對方從電話機接收信號的過程,相當於向socket發送數據和從socket接收數據。通話結束后,一方掛起電話機,相當於關閉socket,撤銷連接。 注意:Socket不僅可以在兩台電腦之間通信,還可以在同一台電腦上的兩個程序間通信,例如TUIO就是利用UDP通信的。
Socket主要有兩種類型:
- 流式Socket
是一種面向連接的Socket,針對於面向連接的TCP服務應用,安全,但是效率低
2,數據報式Socket
是一種無連接的Socket,對應於無連接的UDP服務應用,不安全,但效率高
我們這里主要是講一下UDP通信,TCP通信的話首先需要開啟服務端通信,然后客戶端才可以去連接,服務端與客戶端代碼是不一樣的,連接后是不會斷開的,所以不會出現數據丟失的情況,但效率很低。UDP的話是非連接的,所以不存在服務端和客戶端的區別。各主機之間都是平級的,發送信息的話,UDP建立socket通信后只需要知道對方的IP與端口,直接發送信息就好,它不管信息是否對方是否收到,我只管發,所以可能會出現對方不在線或者其他原因沒有接受到信息的情況,UDP接受消息是只要是發給我的我就統統接受,所以UDP的收發消息大概是這么個情況,因為UDP的靈活,高效性,所以多用於中控程序。
socket通信端口號范圍:0-65535,總共能表示65536個數。
按端口號可分為3大類
(1)公認端口(WellKnownPorts):從0到1023,它們緊密綁定(binding)於一些服務。通常這些端口的通訊明確表明了某種服務的協議。例如:80端口實際上總是HTTP通訊。
(2)注冊端口(RegisteredPorts):從1024到49151。它們松散地綁定於一些服務。也就是說有許多服務綁定於這些端口,這些端口同樣用於許多其它目的。例如:許多系統處理動態端口從1024左右開始。
(3)動態和/或私有端口(Dynamicand/orPrivatePorts):從49152到65535。理論上,不應為服務分配這些端口。實際上,機器通常從1024起分配動態端口。
我們利用UDP通信的時候綁定端口,取1024到49151就好,接下來上代碼,這是一個單例腳本,無需掛載,程序開始時調用一下ConnectStart方法開啟通信就好,記得關閉程序時要調用一下Close1方法來關閉開啟的線程,否則調試的時候線程一直開啟着,可能會出現程序卡死的情況。
*********************************** * Description:udp通信 * Mountpoint:單例無需掛載 * Date:2019 * Version:版本 * Author:LJF ***********************************/ using System.Collections; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using UnityEngine; using LjfLog; public class UDPclient{ static UDPclient instance; public static UDPclient Instance { get { if (instance == null) instance = new UDPclient(); return instance; } } Socket sock; //本機ip、端口 IPEndPoint ip; //用來接收消息的any EndPoint ipany; //接收方的IP端口 IPEndPoint ie; Thread ReceiveListern; //Dictionary<string, NetObject> netObjectDic = new Dictionary<string, NetObject>();//網絡對象字典 public void ConnectStart(int port) { Debuger.EnableSave = true; sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); //sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);//開啟群發功能 //ie = new IPEndPoint(IPAddress.Broadcast,5555);//廣播端口 ip = new IPEndPoint(IPAddress.Parse(GetHostIpAddress()), port); sock.Bind(ip); Debug.Log("服務器啟動了"); // IPEndPoint end = new IPEndPoint(IPAddress.Any, 0); ipany = (EndPoint)end; ReceiveListern = new Thread(Receive); ReceiveListern.Start(); } public string str; public bool isaccept; //收消息 public void Receive() { while (true) { byte[] byt = new byte[1024]; int length = sock.ReceiveFrom(byt, ref ipany); if (length > 0) { isaccept = true; str = Encoding.UTF8.GetString(byt, 0, length); Debuger.Log(string.Format("收到主機:{0}發來的消息|{1}", ipany, str)); } } } //發消息 單發 public void SendMessage(string msg) { byte[] byt = new byte[1024];//1K byt = Encoding.UTF8.GetBytes(msg); //sock.SendTo(byt, byt.Length, SocketFlags.None,ie);//ie為接收方的iP端口 } //動態獲取自身ip private string GetHostIpAddress() { string name = Dns.GetHostName(); IPAddress[] ipadrlist = Dns.GetHostAddresses(name); foreach (IPAddress ipa in ipadrlist) { if (ipa.AddressFamily == AddressFamily.InterNetwork) return ipa.ToString(); } return ""; } //釋放線程、Sock資源 public void Close1() { if (ReceiveListern != null) { ReceiveListern.Abort(); } if (sock != null) { sock.Close(); } Debuger.Dispose(); } //void OnApplicationQuit() //{ //} //void OnDestory() //{ //} }