zoukankan      html  css  js  c++  java
  • U3D Socket实现简易通讯

      Step1:创建工具类 NetWorkManger 实现服务器和客户端的连接和消息的发送

      

    创建该类需要导入命名空间:
    using System;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    将工具类设置为单例类:
    public class NetWorkManger
    {
        #region 单例类
        private static NetWorkManger instance;
        private NetWorkManger ()
        {
        }
        public static NetWorkManger Instance {
            get {
                if (instance == null) {
                    instance = new NetWorkManger ();
                }
                return instance;
            }
        }
        #endregion
    /// <summary>
        /// 定义一个委托类型,只要方法类型为该类型,即可通过该委托进行自动回调(这里用在发送消息和接收回调)
        /// </summary>
        public delegate void MyCallBack (string msg);

     服务器端 方法

    #region 服务器端
    
        /*
         * 服务器的创建流程
         * 1、创建服务器
         * 2、等待客户端连接
         * 3、发送消息
         * 4、接收消息
         * 
         * 使用到的socket中的哪些方法
         * 1、创建套接字(socket)的方法
         * 2、绑定端口号和IP的方法
         * 3、监听连接的方法
         * 4、接收客户端请求的方法(Accept)
         * 5、收发消息的方法
        */
    
        /// <summary>
        /// 服务器委托回调对象,主要向外界传送消息,
        /// 用作服务器向外传值
        /// </summary>
        MyCallBack m_serverCallBack;
        /// <summary>
        /// 服务器端套接字对象
        /// </summary>
        Socket m_serverSocket;
        /// <summary>
        /// 服务器端的输入输出缓冲区域
        /// </summary>
        byte[] m_serverBuffer;
    
        /// <summary>
        /// 初始化服务器
        /// </summary>
        /// <param name="userCallBack">外界传入的方法</param>
        public void ServerInit (MyCallBack userCallBack)
        {
            m_serverCallBack = userCallBack;
            //实例化输入输出的数组
            m_serverBuffer = new byte[1024];
            //实例化socket
            m_serverSocket = new Socket (
                //使用IP地址类型为IPv4
                AddressFamily.InterNetwork,
                //套接字类型为TCP的流式传输
                SocketType.Stream,
                //选取协议为TCP协议
                ProtocolType.Tcp
            );
            /// <summary>
            /// 绑定IP地址和端口号
            /// IPAddress.Any:表示接受所有连接的IP地址
            /// 34567:表示端口号,IP表示是哪个电脑,
            ///        端口指哪个服务(哪个应用)
            /// </summary>
            IPEndPoint point = 
                new IPEndPoint (IPAddress.Any, 34567);
            //将节点绑定到socket上
            m_serverSocket.Bind (point);
            //开始监听(如果监听成功,服务器就启动成功了,
            //10表示能接受到的最大连接数)
            m_serverSocket.Listen (10);
            //将服务器启动成功的消息发送出去
            m_serverCallBack ("服务器启动成功");
            //开始接收,进入等待客户端的连接的状态
            //第一个参数:这是一个方法名字,等到有客户端连接时
            //          自动回调的方法,这个方法需要传入一个
            //          IAsyncResult类型的参数,这个方法一旦
            //          开启,就会开启一个子线程,直到有人连接
            //          会通知主线程,通知的内容就是这个IAsyncResult
            //第二个参数:对应当前监听连接的socket
            m_serverSocket.BeginAccept (
                ServerAccept, m_serverSocket
            );
        }
    
        /// <summary>
        /// 当服务器接收到用户的连接请求时的回调方法
        /// </summary>
        /// <param name="ar">子线程向主线程传递
        /// 的有客户端连接的信息</param>
        void ServerAccept (IAsyncResult ar)
        {
            
            //当客户端连接时,获取到当前子线程中等待的socket
            m_serverSocket = ar.AsyncState as Socket;
            //接收结果,这是一个新的socket
            Socket workingSocket =
                m_serverSocket.EndAccept (ar);
            //开始基于建立新的socket进行收发消息
            workingSocket.BeginReceive (
                //收发缓存区
                m_serverBuffer,
                //起始位置
                0,
                //接收数据的长度
                m_serverBuffer.Length,
                //接收过程中是否包含特殊标记
                SocketFlags.None,
                //接收到消息后的回调方法
                ServerReceive,
                //当前的套接字状态
                workingSocket
            );
            //尾递归
            m_serverSocket.BeginAccept (
                ServerAccept, m_serverSocket);
        }
    
        /// <summary>
        /// 服务器接收到消息的回调方法
        /// </summary>
        /// <param name="ar">Ar.</param>
        void ServerReceive (IAsyncResult ar)
        {
            Socket workingSocket = ar.AsyncState as Socket;
            //接收到的字节数据
            int count = workingSocket.EndReceive (ar);
            //将字节数据转成字符串
            string msgResult = 
                UTF8Encoding.UTF8.GetString (m_serverBuffer);
            //回调
            m_serverCallBack ("收到了" + count + "字节数据");
            m_serverCallBack (msgResult);
            m_serverBuffer = new byte[1024];
            //尾递归
            workingSocket.BeginReceive (
                m_serverBuffer,
                0,
                m_serverBuffer.Length,
                SocketFlags.None,
                ServerReceive,
                workingSocket
            );
        }
        #endregion
     

    客户端方法封装

    #region 客户端
    
        /// <summary>
        /// 客户端套接字.
        /// </summary>
        Socket m_clientSocket;
    
        /// <summary>
        /// 客户端委托回调
        /// </summary>
        MyCallBack m_clientCallback;
    
        /// <summary>
        /// 客户端数据缓存区域
        /// </summary>
        byte[] m_clientBuffer;
    
        /// <summary>
        /// 客户端连接服务端的方法
        /// </summary>
        /// <param name="ip">要连接的IP地址</param>
        /// <param name="port">端口号</param>
        /// <param name="uerCallBack">消息回调</param>
        public void ClientConnect (
            string ip, int port, MyCallBack uerCallBack)
        {
            m_clientSocket = new Socket (
                AddressFamily.InterNetwork,
                SocketType.Stream,
                ProtocolType.Tcp
            );
            //初始化客户端数据缓存区域
            m_clientBuffer = new byte[1024];
    
            //连接服务器,IPAddress.Parse:解析IP
            m_clientSocket.Connect (
                IPAddress.Parse (ip), port);
            //消息回调
            m_clientCallback = uerCallBack;
            m_clientCallback ("服务器连接成功");
            //开始接收消息
            m_clientSocket.BeginReceive (
                m_clientBuffer,
                0,
                m_clientBuffer.Length,
                SocketFlags.None,
                ClinetReceive,
                m_clientSocket
            );
        }
    
        /// <summary>
        /// 客户端接收到消息后回调的方法
        /// </summary>
        /// <param name="ar">Ar.</param>
        void ClinetReceive (IAsyncResult ar)
        {
            Socket workingSocket = ar.AsyncState as Socket;
            //接收到的字节数目
            int count = workingSocket.EndReceive (ar);
            //将接收到的数据转成字符串
            string msgResult =
                UTF8Encoding.UTF8.GetString (m_clientBuffer);
            m_clientCallback ("收到了" + count + "字节数据");
            //对外进行回调
            m_clientCallback (msgResult);
            //重置一下buffer
            m_clientBuffer = new byte[1024];
            //开始接收消息(递归接收)
            m_clientSocket.BeginReceive (
                m_clientBuffer,
                0,
                m_clientBuffer.Length,
                SocketFlags.None,
                ClinetReceive,
                workingSocket
            );
        }
    
        /// <summary>
        /// 客户端发送消息的方法
        /// </summary>
        /// <param name="msg">Message.</param>
        public void ClientSend (string msg)
        {
            //将要发送的内容转成字节数组
            m_clientBuffer = 
                UTF8Encoding.UTF8.GetBytes (msg);
            //开始发送
            m_clientSocket.BeginSend (
                m_clientBuffer,
                0,
                m_clientBuffer.Length,
                SocketFlags.None,
                //数据发送成功之后的回调
                SendSucces,
                m_clientSocket
            );
        }
    
        /// <summary>
        ///  客户端发送数据成功的回调方法
        /// </summary>
        /// <param name="ar">Ar.</param>
        void SendSucces (IAsyncResult ar)
        {
            //发送成功,获得发送成功的socket
            Socket workingSocket = ar.AsyncState as Socket;
            //结束发送
            workingSocket.EndSend (ar);
        }
        #endregion

    step2:创建服务器场景-Server(接收消息)

    public class ServerScript : MonoBehaviour
    {
        Text m_text;
        string m_currentMsg;
        void Awake ()
        {
            //保证程序后台运行
            Application.runInBackground = true;
        }
        void Start ()
        {
            m_text = GameObject.Find ("Text").GetComponent<Text> ();
            //创建服务器
            NetWorkManger.Instance.ServerInit ((string msg) => {
                //将服务器传递过来的数据接收一下
                m_currentMsg = msg;
            });
            m_text.text = m_currentMsg;
        }
        void Update ()
        {
            //将接受到的数据放到Text中
            m_text.text = m_currentMsg;
        }

    step3:创建客户端服务器-Client(发送消息)

    public class ServerScript : MonoBehaviour
    {
    
        Text m_text;
    
        string m_currentMsg;
    
        void Awake ()
        {
            //保证程序后台运行
            Application.runInBackground = true;
        }
    
        void Start ()
        {
            m_text = GameObject.Find ("Text").GetComponent<Text> ();
            //创建服务器
            NetWorkManger.Instance.ServerInit ((string msg) => {
                //将服务器传递过来的数据接收一下
                m_currentMsg = msg;
            });
            m_text.text = m_currentMsg;
        }
    
        void Update ()
        {
            //将接受到的数据放到Text中
            m_text.text = m_currentMsg;
        }
    }
  • 相关阅读:
    ETL之Kettle
    java 之webmagic 网络爬虫
    【AC自动机】【树状数组】【dfs序】洛谷 P2414 [NOI2011]阿狸的打字机 题解
    【AC自动机】【字符串】【字典树】AC自动机 学习笔记
    【前缀和】【two-pointer】【贪心】洛谷 P3143 [USACO16OPEN]钻石收藏家Diamond Collector 题解
    【KMP】【矩阵加速】【递推】洛谷 P3193 [HNOI2008]GT考试 题解
    【KMP】洛谷P2375 [NOI2014]动物园 题解
    【KMP】【字符串】KMP字符串匹配算法 学习笔记
    【DP】+【贪心】【前缀和】洛谷P2893 [USACO08FEB]修路Making the Grade 题解
    【字典树】【树】【二进制】bzoj1954/POJ3764The xor-longest Path 题解
  • 原文地址:https://www.cnblogs.com/zpy1993-09/p/13083259.html
Copyright © 2011-2022 走看看