C# Socket之UDP通信
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() //{ //} }