制作UDPNetMgr网络管理模块
这段代码定义了一个名为UDPNetMgr
的 Unity 脚本类,用于管理 UDP 网络通信,它作为单例存在,在Awake
方法中创建收发消息的线程,Update
方法处理接收到的消息;StartClient
方法启动客户端连接,ReceiveMsg
和SendMsg
方法分别用于接收和发送消息,Send
方法将消息加入发送队列,Close
方法关闭套接字并发送退出消息,同时在脚本销毁时自动调用关闭操作
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;public class UDPNetMgr : MonoBehaviour
{ private static UDPNetMgr instance;public static UDPNetMgr Instance => instance;private EndPoint serverIpPoint;public Socket socket;private bool IsClose=true;public byte[] cacheBytes = new byte[512];//创建两个队列来收消息和发消息public Queue<BaseMsg> sendMsgQueue = new Queue<BaseMsg>();public Queue<BaseMsg> receiveMsgQueue = new Queue<BaseMsg>();void Awake(){instance = this;DontDestroyOnLoad(this.gameObject);//创建两个线程来执行收发消息ThreadPool.QueueUserWorkItem(ReceiveMsg);ThreadPool.QueueUserWorkItem(SendMsg);}// Update is called once per framevoid Update(){if(receiveMsgQueue .Count >0){BaseMsg basemsg = receiveMsgQueue.Dequeue();switch (basemsg ){case PlayerMsg msg:print(msg.playerID);print(msg.playerData .atk);print(msg.playerData .lev);print(msg.playerData .name);break;}}}//启动客户端Socket的方法public void StartClient(string ip,int port){if (!IsClose)return;//记录远端服务器的Ip和端口号serverIpPoint = new IPEndPoint(IPAddress.Parse(ip), port);IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8081);try{socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);socket.Bind(ipPoint);IsClose = false;print("客户端网络启动");}catch (System.Exception e){print("启动客户端Socket失败" + e.Message);}}//接收消息的方法public void ReceiveMsg(object obj){EndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 0);int msgID;int nowIndex;int msgLength;while (socket!=null&&!IsClose){try{socket.ReceiveFrom(cacheBytes, ref ipEndPoint);//为了避免非服务器发来的骚扰消息if (!ipEndPoint.Equals(serverIpPoint))continue;//如果不是服务器发来的消息,就不处理了//处理服务器发来的消息nowIndex = 0;//解析IDmsgID = BitConverter.ToInt32(cacheBytes, nowIndex);nowIndex += 4;//解析消息长度msgLength = BitConverter.ToInt32(cacheBytes, nowIndex);nowIndex += 4;//解析消息体BaseMsg msg = null;switch (msgID){case 1001:msg = new PlayerMsg();//反序列化消息体msg.Reading(cacheBytes, nowIndex);break;}if (msg != null)receiveMsgQueue.Enqueue(msg);}catch (SocketException s){print("接收消息出问题" + s.SocketErrorCode + s.Message);}catch (System.Exception e){print("接收消息出问题(非网络问题)" + e.Message);}}}//发送消息的方法public void SendMsg(object obj){while (socket!=null&&!IsClose){if(sendMsgQueue .Count >0){try{socket.SendTo(sendMsgQueue.Dequeue().Writing(), serverIpPoint);}catch (SocketException e){print("发送消息失败" + e.SocketErrorCode + e.Message);}}}}public void Send(BaseMsg msg){sendMsgQueue.Enqueue(msg);}//关闭socketpublic void Close(){if(socket!=null){IsClose = true;quitMsg quitMsg = new quitMsg();//发送一个退出消息给服务器,让他移除记录socket.SendTo(quitMsg.Writing(), serverIpPoint);socket.Shutdown(SocketShutdown.Both);socket.Close();}}private void OnDestroy(){Close();}
}
启动UDP客户端
MainUDP
类继承自MonoBehaviour
,是一个 Unity 脚本。它的主要功能是在游戏开始时确保UDPNetMgr
单例实例存在,然后启动 UDP 客户端并连接到指定的服务器地址和端口。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class MainUDP : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){if(UDPNetMgr .Instance ==null){GameObject obj = new GameObject("UdpNet");obj.AddComponent<UDPNetMgr>();}UDPNetMgr.Instance.StartClient(("127.0.0.1"), 8080);}// Update is called once per framevoid Update(){}
}
让客户端给服务器发消息
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class Lesson15 : MonoBehaviour
{public Button btn;// Start is called before the first frame updatevoid Start(){btn.onClick.AddListener(() =>{PlayerMsg playerMsg = new PlayerMsg();playerMsg.playerID = 1;playerMsg.playerData.atk = 888;playerMsg.playerData.lev = 999;playerMsg.playerData.name = "DamnF客户端发来的消息";UDPNetMgr.Instance.Send(playerMsg);});}// Update is called once per framevoid Update(){}
}
实现客户端和服务器同步通信
运行服务器,启动客户端,使客户端和服务器实现UDP同步通信