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
}

 

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

posted on 2019-12-27 11:21  嗜睡的熊大  阅读(2485)  评论(0编辑  收藏  举报

导航