服務器下使用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 }