前言


上一篇简单的介绍了下Unity客户端和服务器的Socket通信,但是还不能实现多个客户端与服务器的通信,所以今天在这边把前面的工程完善一下(使用的是上篇讲到的UdpClient类来实现),实现多个客户端与服务器的udp通信。效果图如下,两个客户端可以向服务器发送消息,然后服务器每隔3秒给“连接上”的客户端发送收到的消息。



内容

思路上一篇已经讲到过了,我们定义两个特殊的字段,来告知服务器,哪些客户端连接上来了,哪些客户端退出了,如下脚本,该脚本客户端服务器各存一份。
namespace Tool { class SocketDefine { public const int port = 8078;//端口号
public const string ip = "127.0.0.1"; public const string udpConnect =
"udpConnect";//udp连接 public const string udpDisconnect =
"udpDisconnect";//udp断开连接 } }
服务器端


服务器相比之前要做的就是,当接收到udpConnect信息时要记录下发该消息的客户端ip地址,保存在一个字典中,字典不为空的时候,每隔三秒给字典中存在的客户端发送消息(简单测试,目前服务器给各个客户端发的消息就是客户端发给服务器的最新消息)。当收到udpDisconnect消息时,将该客户端从字典中删除即可。同时我们定义一个新的类ClientMessage,用于存放客户端数据。具体代码如下:
using System; using System.Collections.Generic; using System.Net; using
System.Net.Sockets; using System.Threading; namespace Tool { public class
ClientMessage { /// <summary> /// 每个客户端的唯一id,即ip地址+端口号 /// </summary> public
string clientId; /// <summary> /// 客户端地址信息 /// </summary> public IPEndPoint
clientIPEndPoint; /// <summary> /// 该客户端发送给服务器的最新消息 /// </summary> public
string recieveMessage; public ClientMessage(string id, IPEndPoint point, string
msg) { clientId = id; clientIPEndPoint = new IPEndPoint(point.Address,
point.Port); recieveMessage = msg; } } class UdpManager :
SingleClass<UdpManager> { UdpClient m_udpClient; IPEndPoint
m_clientIpEndPoint;//存放客户端地址 Thread m_connectThread;//接收客户端消息的线程 byte[]
m_result = new byte[1024];//存放接收到的消息 int m_sendCount;//发送次数 Dictionary<string,
ClientMessage> m_clientMessageDic;//存放客户端信息,key->ip+port //初始化 public void
Start() { IPEndPoint ipEnd = new IPEndPoint(IPAddress.Parse(SocketDefine.ip),
SocketDefine.port); m_udpClient = new UdpClient(ipEnd); m_clientMessageDic =
new Dictionary<string, ClientMessage>(); m_sendCount = 0; //定义客户端
m_clientIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
Console.WriteLine("等待连接数据"); //开启一个线程连接 m_connectThread = new Thread(new
ThreadStart(Receive)); m_connectThread.Start(); //定时器 System.Timers.Timer t =
new System.Timers.Timer(3000);//实例化Timer类,设置间隔时间为3000毫秒 t.Elapsed += new
System.Timers.ElapsedEventHandler(SendToClient);//到达时间的时候执行事件 t.AutoReset =
true;//设置是执行一次(false)还是一直执行(true) t.Enabled =
true;//是否执行System.Timers.Timer.Elapsed事件 } public void SendToClient(object
source, System.Timers.ElapsedEventArgs e) { Send(GetAllClientMessage()); }
public void Send(string data) { if(m_clientMessageDic == null ||
m_clientMessageDic.Count == 0) { return; } try { NetBufferWriter writer = new
NetBufferWriter(); writer.WriteString(data); byte[] msg = writer.Finish();
foreach(var point in m_clientMessageDic) { Console.WriteLine("send to " +
point.Key + " " + data); m_udpClient.Send(msg, writer.finishLength,
point.Value.clientIPEndPoint); } m_sendCount++; } catch(Exception ex) {
Console.WriteLine("send error " + ex.Message); } } //服务器接收 void Receive() {
while(true) { try { m_result = new byte[1024]; m_result =
m_udpClient.Receive(ref m_clientIpEndPoint); NetBufferReader reader = new
NetBufferReader(m_result); string data = reader.ReadString(); string clientId =
string.Format("{0}:{1}", m_clientIpEndPoint.Address, m_clientIpEndPoint.Port);
if(data.Equals(SocketDefine.udpConnect)) { AddNewClient(clientId, new
ClientMessage(clientId, m_clientIpEndPoint, data)); } else
if(data.Equals(SocketDefine.udpDisconnect)) { RemoveClient(clientId); } else {
if(m_clientMessageDic != null && m_clientMessageDic.ContainsKey(clientId)) {
m_clientMessageDic[clientId].recieveMessage = data; } }
Console.WriteLine(m_clientIpEndPoint + " 数据内容:{0}", data); } catch(Exception
ex) { Console.WriteLine("receive error " + ex.Message); } } } //连接关闭 void
Close() { //关闭线程 if(m_connectThread != null) { m_connectThread.Interrupt();
//Thread abort is not supported on this platform. //m_connectThread.Abort();
m_connectThread = null; } m_clientMessageDic.Clear(); if(m_udpClient != null) {
m_udpClient.Close(); m_udpClient.Dispose(); } Console.WriteLine("断开连接"); } void
AddNewClient(string id, ClientMessage msg) { if(m_clientMessageDic != null &&
!m_clientMessageDic.ContainsKey(id)) { m_clientMessageDic.Add(id, msg); } }
void RemoveClient(string id) { if(m_clientMessageDic != null &&
m_clientMessageDic.ContainsKey(id)) { m_clientMessageDic.Remove(id); } } string
GetAllClientMessage() { string allMsg = "m_sendCount " + m_sendCount + "\n";
foreach(var msg in m_clientMessageDic) { allMsg += (msg.Value.clientId + "->" +
msg.Value.recieveMessage + "\n"); } return allMsg; } } }
服务器

服务器就更简单啦,connect的时候给服务器发送一个udpConnect消息,断开的时候发送一个udpDisconnect消息即可。
using System; using System.Net; using System.Net.Sockets; using
System.Threading; using UnityEngine; namespace Tool { public class UdpManager :
SingleClass<UdpManager>, ISocket { public delegate void OnGetReceive(string
message);//接收到消息的委托 public OnGetReceive onGetReceive; byte[] m_result = new
byte[1024]; Thread m_connectThread; UdpClient m_udpClient; IPEndPoint
m_serverIPEndPoint; IPEndPoint m_recieveIPEndPoint; bool m_isConnected;
//是否已连接的标识 public bool IsConnected() { return m_isConnected; }
//udp是无连接的,所以方法里只做了一些初始化操作 public void Connect(string ip, int port) {
m_serverIPEndPoint = new IPEndPoint(IPAddress.Parse(ip), port); m_udpClient =
new UdpClient(0);//!!!!!主要一定要设置port为0,不然无法接收到服务器的消息 m_isConnected = true;
m_recieveIPEndPoint = new IPEndPoint(IPAddress.Any, 0); //开启一个线程连接
m_connectThread = new Thread(new ThreadStart(RecieveMessage));
m_connectThread.Start(); SendMessage(SocketDefine.udpConnect); } public void
SendMessage(string data) { if(IsConnected()) { NetBufferWriter writer = new
NetBufferWriter(); Debug.Log("SendMessage " + data); writer.WriteString(data);
m_udpClient.Send(writer.Finish(), writer.finishLength, m_serverIPEndPoint); } }
public void Disconnect() { SendMessage(SocketDefine.udpDisconnect);
if(m_connectThread != null) { m_connectThread.Interrupt(); //在调用此方法的线程上引发
ThreadAbortException,以开始终止此线程的过程。 调用此方法通常会终止线程。 m_connectThread.Abort(); }
if(IsConnected()) { Debug.Log("Disconnect"); m_isConnected = false; }
if(m_udpClient != null) { m_udpClient.Close(); } } public void RecieveMessage()
{ while(IsConnected()) { try { m_result = new byte[1024];
//m_udpClient的port不是0的时候,会报错,无效参数 m_result = m_udpClient.Receive(ref
m_recieveIPEndPoint); NetBufferReader reader = new NetBufferReader(m_result);
string msg = reader.ReadString(); Debug.Log("RecieveMessage " + msg);
if(onGetReceive != null) { onGetReceive(msg); } } catch(Exception e) {
Debug.Log("recieve error " + e.Message); } } } } }
这样就可以实现最简单的多客户端和服务器的udp通信了

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信