服务器下使用Socket_UDP协议怎么实现局域网内广播和接收
一开始接到这个项目需求时,其实挺懵逼的。因个人目前经验并不多,想过各种实现方案也利用TCP UDP 个人实验了不下10次,
总算再网上找到借鉴的同时开发出目前适合自己项目的一种方案。下面就来分享我的代码(如有不同意见还望指正):
using System; using System.Text; using System.Threading; using UnityEngine; using System.Net.Sockets; using System.Net; using System.Collections; using System.Collections.Generic; public class Glowworm : MonoBehaviour { private bool isFirstStart = false; //广播 private Socket socket; private IPEndPoint iep1; private byte[] data = new byte[2048 * 3]; public int udpPort = 9090; private float intervalTime = 2.0f; private bool isIntervalSend = false; private float curTime = 0; //接收 private byte[] data_Receive = new byte[2048 * 3]; //private string Error_Message; private Thread t_Reveive; private EndPoint ep; private bool IsStop = false; private Socket UDPReceive; //解析 private List<string> allCallBackMessList = new List<string>(); private string CallBackMessage; private static SocketMsgData socketMsgData = null; //事件管理 //保持socket消息与主线程同步 private ManualResetEvent allDone = new ManualResetEvent(false); private static readonly object Lock = new object(); //s锁 //单例 private static Glowworm instance; public static Glowworm Instance { get { return instance; } } #region 事件函数 public void Awake() { if (instance == null) { instance = this; DontDestroyOnLoad(gameObject); isFirstStart = true; } else { Destroy(gameObject); return; } } private void Start() { isFirstStart = true; //广播 //BroadcastIP(); } private void Update() { //if (Input.GetKeyDown(KeyCode.Q)) //{ // Send("3333333333333333333333333333"); //} //类似心脏跳动检测 定时2秒一次(广播告知所有局域网内IP) curTime += Time.fixedDeltaTime; if (curTime >= intervalTime && isIntervalSend) { Send("0_0_0_0"); curTime = 0; } //信息处理 if (socketMsgData != null) { lock (Lock) { if(socketMsgData.MessageType == (int)MessageType.Register) { //如果是再创建则需要保证被管控 Server.curAcceptUserTravel = socketMsgData.TravelSceneObj; Debug.Log(Server.curAcceptUserTravel); } CheckDataObjState(socketMsgData); Debug.Log("Update"); } socketMsgData = null; allDone.Set(); } } #endregion #region 自定义函数 //update 中检测信息对象函数 public void CheckDataObjState(SocketMsgData _socketMsgData) { Debug.Log(_socketMsgData.ToString()); //获取临时路径 //注意 这个也判断了是否需要接入数据库的路径 string tmpUrlPath = PathManager.Instance.GetSendToWebMssager(_socketMsgData); if (string.IsNullOrEmpty(tmpUrlPath)) { return; } else { //如果路径不为空则接入数据库 _socketMsgData.m_urlPath = WebSeverHandler.Instance.WebServerConfig + tmpUrlPath; Debug.Log(_socketMsgData.m_urlPath); //获取 StartCoroutine(WebSeverHandler.Request(_socketMsgData, CallBackEventFunction)); } } //事件回调函数 public void CallBackEventFunction(object _callBackMsg) { SocketMsgData dataObj = _callBackMsg as SocketMsgData; Debug.Log(dataObj.callMessage); switch ((MessageType)dataObj.MessageType) { case MessageType.Student: { if (!string.IsNullOrEmpty(dataObj.callMessage) && dataObj.callMessage.Length > 2) { dataObj.callMessage = "1"; Debug.Log(dataObj.callMessage); } else { dataObj.callMessage = "0"; Debug.Log(dataObj.callMessage); } break; } case MessageType.Teacher: { if (!string.IsNullOrEmpty(dataObj.callMessage) && dataObj.callMessage.Length > 2) { dataObj.callMessage = "1"; Debug.Log(dataObj.callMessage); } else { dataObj.callMessage = "0"; Debug.Log(dataObj.callMessage); } break; } case MessageType.CreateInfo: { break; } case MessageType.MoveInfo: { break; } case MessageType.DestroyInfo: { break; } case MessageType.AsynInfo: { break; } case MessageType.ResultCheck: { break; } case MessageType.TestPaperdownLoad: { break; } case MessageType.ScoreChange: { break; } default: break; } this.Send(dataObj.ToString()); //直接发送是否登录 //Send(_callBackMsg + "192.168.5.199_1"); Debug.Log(dataObj.callMessage); } #endregion #region udp 广播和接收 //广播 public void BroadcastIP() { if(isFirstStart) //判断是否第一次打开 { socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); iep1 = new IPEndPoint(IPAddress.Broadcast, udpPort); data = Encoding.UTF8.GetBytes("111"); socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1); isIntervalSend = true;//开始间隔广播 StartReceive(); //开始接收 isFirstStart = false; } else { IsStop = false; //继续间隔发送 isIntervalSend = true; //继续接收 StartReceive(); //开始接收 } } //广播发送 public void Send(string msg) { msg += "#"; Debug.Log(msg); data = Encoding.UTF8.GetBytes(msg); socket.SendTo(data, iep1); } //接收 private void StartReceive() { try { //UDPReceive = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); ep = new IPEndPoint(IPAddress.Any, udpPort); //socket.Bind(ep); data_Receive = new byte[2048*3]; t_Reveive = new Thread(Receive); t_Reveive.IsBackground = true; t_Reveive.Start(); } catch (Exception e) { Debug.LogError("错误信息:" + e.Message); } } //线程中执行函数 private void Receive() { while (!IsStop) { if (socket.Available <= 0) continue; int recv = socket.ReceiveFrom(data_Receive, ref ep); if(recv > 0) { string msg = Encoding.UTF8.GetString(data_Receive, 0, recv); Debug.Log("接收消息:" + msg); allCallBackMessList.Clear(); //清空 //解析包 AnalyzePackage(msg); //分离出集合中信息对象并进行数据处理 foreach (string mess in allCallBackMessList) { string[] tmpArray = mess.Split('_'); //string.IsNullOrEmpty(tmpArray[1]) && string.IsNullOrEmpty(tmpArray[2] if (tmpArray.Length < 1) { continue; } else { // 消息处理 allDone.Reset(); //事件管控 保证下列事件只有一个线程在使用(避免争抢) socketMsgData = new SocketMsgData(); socketMsgData.InitData(); socketMsgData.SetMessage2Obj(mess); Debug.Log(socketMsgData.ToString()); //SplitMsgType(socketMsgData); //初步分割 allDone.WaitOne(); //等待主线程执行 } //把收到的数据再次发送给原始目标 //Send(mess); Debug.Log(mess); } } } } //old 初步信息分割 public void SplitMsgType(SocketMsgData _msgData) { if (_msgData == null) return; switch ((MessageType)_msgData.MessageType) { case MessageType.Student: case MessageType.Teacher: case MessageType.ResultCheck: case MessageType.TestPaperdownLoad: case MessageType.ScoreChange: case MessageType.CreateInfo: case MessageType.MoveInfo: case MessageType.DestroyInfo: case MessageType.AsynInfo: default: break; } } //暂停接收 public void StopReceive() { IsStop = true; t_Reveive.Abort(); isIntervalSend = false; } //解析包的函数 void AnalyzePackage(string message) { CallBackMessage += message; //Debug.Log(CallBackMessage.ToString()); //#作为一条消息的结尾 int index = -1; while ((index = CallBackMessage.IndexOf("#")) != -1) { allCallBackMessList.Add(CallBackMessage.Substring(0, index)); //Debug.Log(CallBackMessage.Substring(0, index)); CallBackMessage = CallBackMessage.Substring(index + 1); } } //程序推出时执行 private void OnApplicationQuit() { //接收 IsStop = true; //广播 isIntervalSend = false; if(socket != null) { socket.Shutdown(SocketShutdown.Both); socket.Close(); } //t_Reveive.Abort(); } #endregion }