本文使用udpclient和tcpclient,而非使用socket实例
命名空间
using System.Net;
using System.Net.Sockets;
TCP
TCP的核心对象为 TcpListener和TcpClient,前者用于服务器监听连接请求,并创建TcpClient对象,当需要通信时,直接使用创建的TcpClient调用Send,Receive方法即可
监听连接: TCP需要进行连接,因此需要一个连接监听器,服务器监听客户端连接如下
/// <summary>
/// TCP连接请求监听者
/// </summary>
private TcpListener tcpListener;
private void Awake()
{
//开启连接监听的线程,必须另开一个线程启动监听,如果在主线程里直接调用,主线程会阻塞
tcpListenerT = new Thread(ListenConnect);
tcpListenerT.IsBackground = true;
tcpListenerT.Start();
}
//监听连接请求的方法
private void ListenConnect()
{
//声明监听者的IP为任意可用`在这里插入代码片`
tcpListener = new TcpListener(new IPEndPoint(IPAddress.Any, 10086));
tcpListener.Start(100);//监听请求 最多连接100个
while (true)
{
//这一步会阻塞线程,不能在主线程中调用
TcpClient client = tcpListener.AcceptTcpClient();
//获取客户端的IP
string ip = (client.Client.RemoteEndPoint as IPEndPoint).Address.ToString();
}
}
客户端连接服务器:
private TcpClient tcpClient = new TcpClient();
private void Start()
{
//参数为服务器的地址,和服务器的TcpListener绑定的端口
tcpClient.Connect("192.168.1.36", 10086);
}
发送消息:
public void SendMsg(TcpClient client,string msg)
{
byte[] buff = Encoding.UTF8.GetBytes(msg);
client.Send(buff);
}
接收消息:
private TcpClient tcpClient = new TcpClient();
private void Start()
{
//连接到服务器
tcpClient.Connect("192.168.1.36", 10086);
//接收消息的方法必须在子线程中执行
tcpReciveT = new Thread(Recciveimage);
tcpReciveT.IsBackground = true;
tcpReciveT.Start();
}
/// <summary>
/// 接收字节数组
/// </summary>
private void Recciveimage()
{
//声明接收缓冲区的长度
byte[] receiveBuff = new byte[1024];
int reviceLength = 0;
while (true)
{
try
{
//返回值为接收到的字节的数量 这一步会阻塞线程,决不能在主线程中执行
reviceLength = tcpClient.Client.Receive(receiveBuff);
//必须指定转换的字节数组的长度,因为缓冲区剩余的空位会用0填充,这些0我们并不需要
msg = Encoding.UTF8.GetString(receiveBuff,0,reviceLength);
isReveive = true;
print("收到的消息 "+msg);
}
}
}
UDP
UDP相对简单,UDP并不需要连接,核心对象为UdpClinent和IPEndPoint
UdpClient即UDP的对象,用于收发消息
IPEndPoint可以理解为Udp通信的端点,解决三个问题 我是谁?我要发到哪里去?我从哪里接收?
声明UdpClient时,需要指定UdpClient的IPEndPoint,即,我是谁
通过UdpClient发送消息时,需要指定目的地的IPEndPoint,即,我要发到哪里去
通过UdpClient接收消息时,需要指定监听的IPEndPoint,即,我从哪里收
IPEndPoint常用的构造有以下两种,都需要我们指定IP和端口,在构造函数中使用IPAddress类指定IP
//IP为当前可用IP,或任意IP 端口为0表示任何端口, 这种声明通常在接收消息中使用
new IPEndPoint(IPAddress.Any, 0)
//指定一个IP,255.255.255.255为群发 端口为40000 指定确定的IP端口通常用于声明UdpClient和发送消息
new IPEndPoint(IPAddress.Parse("192.168.1.36"), 40000)
发送
//公共的消息发送中心
private UdpClient udpClient;
private void Awake()
{
//为UdpClient绑定本机的IP和端口 我是谁
udpClient = new UdpClient(new IPEndPoint(IPAddress.Any, 40000));
}
/// <summary>
/// 消息发送 IPEndPoint声明 IPEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.36"),10000)
/// </summary>
public void CommonendMsgSender(string msg, IPEndPoint commonIPEndPoint)
{
byte[] commonBuff = Encoding.UTF8.GetBytes(msg);
udpClient.Send(commonBuff, commonBuff.Length, commonIPEndPoint);
}
监听
private UdpClient CommonUdpClient;
// 公共的消息接收端口
private IPEndPoint commonReceiveIPEndPoint;
// 公共的消息线程
Thread commonReceiveThread;
// 公共消息的缓存
private byte[] commonMsgBuff;
private void Start()
{
//公共消息接收端口
commonReceiveIPEndPoint = new IPEndPoint(IPAddress.Any, 0);
//启动监听线程,和TCP一样,监听会阻塞线程,不能在主线程中监听消息
commonReceiveThread = new Thread(ListenCommonMsg);
commonReceiveThread.IsBackground = true;
commonReceiveThread.Start();
}
// 监听公共消息
private void ListenCommonMsg()
{
while (true)
{
//这里会阻塞线程
commonMsgBuff = CommonUdpClient.Receive(ref commonReceiveIPEndPoint);
string temp = Encoding.UTF8.GetString(commonMsgBuff);
print("公共消息为" + temp);
}
}
注意事项
1 监听操作必须在子线程中执行,不要在主线程中执行,否则主线程会被阻塞
2 重复监听消息应该使用死循环
3 子线程可以操作主线程的简单属性,如果 int bool str,但不能直接操作Uinty对象如Text等,如果需要在接收消息后改变场景内容 ,在一个主线程的脚本中的Update里,使用一个bool制作一把锁,将子线程收到的消息,赋值给主线程脚本的string变量,并将锁置为true,使用这个脚本来控制Uinty对象
例
//子线程接到消息后,置为true
public bool isReceive = false;
/// <summary>
/// 子线程接到消息后,将消息赋值到这个变量
/// </summary>
public string msg;
void Update()
{
if (isReceive)
{
//处理msg
if(msg == "1")
{
//逻辑
}
}
}