Socket之间的通信可以类比生活中打电话的案例。任何用户在通话之前,首先要占有一部电话机,相当于申请一个Socket,同时要知道对方的号码,相当于对方有一个固定的Socket,然后向对方拨号呼叫,相当于发出连接请求。假如对方在场并空闲,拿起 电话话筒,双方就可以进行通话了。双方的通话过程,是一方向电话机发出信号和对方从电话机接收信号的过程,相当于向socket发送数据和从socket接收数据。通话结束后,一方挂起电话机,相当于关闭socket,撤销连接。 注意:Socket不仅可以在两台电脑之间通信,还可以在同一台电脑上的两个程序间通信,例如TUIO就是利用UDP通信的。
Socket主要有两种类型:
1,流式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()
//{
//}
}