unity_服務器下使用Socket_UDP實現局域網廣播和接收(個人筆記)


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

 

本篇文章屬於個人筆記,有不同意見的,還望指正,希望自己能更好的再編程路上走下去。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM