zoukankan      html  css  js  c++  java
  • 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
    }

    本篇文章属于个人笔记,有不同意见的,还望指正,希望自己能更好的再编程路上走下去。

  • 相关阅读:
    nginx
    spring 学习
    mysql 免安装 操作
    院感干预 报错
    iis 无法绑定 net.tcp
    wangEditor 自定义 菜单
    院感干预 发布
    第17篇 shell编程基础(2)
    第16篇 Shell脚本基础(一)
    第15篇 PSR-04 规范
  • 原文地址:https://www.cnblogs.com/Roz-001/p/12106352.html
Copyright © 2011-2022 走看看