zoukankan      html  css  js  c++  java
  • Unity3d网络总结(三) 封装Socket创建简单网络

    北京又在打雷下大雨了,学习Unity以来,越来越感兴趣,情不自禁的想要学习更多知识

    这次自己搭建一个Socket模块,比较基础,适合新手学习,详细介绍Socket的搭建过程,同样会把详细过程在代码里进行注释~

    在搭建Socket过程中,需要创建以下几个常用的方法:

    1.创建套接字(socket)

    2.绑定Ip和端口

    3.监听方法

    4.接收客户端请求的方法

    5.收发消息的方法

    创建SocketManger管理类

    把客户端与服务端代码都写在新建的SocketManger里,并把SocketManger写成单例,方便调用

    using System.Net;
    //引入套接字协议类
    using System.Net.Sockets;
    using System;
    using System.Text;
    
    public class SocketManager {
        #region 单例类
        private static SocketManager instance;
        private SocketManager()
        {
        }
        public static SocketManager Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new SocketManager();
                }
                return instance;
            }
        }
        #endregion
    
        public delegate void MyCallBack(string msg);    //声明一个委托类型,在服务器和客户端工作的时候,会使用这个回调方法反馈当前交互的具体情况

    服务端代码

    #region 服务器代码
        /* 创建服务器
         * 等待客户端的连接
         * 接受消息
         */
        Socket serverSocket;             //创建服务器的套接字对象
        MyCallBack serverCallBack;       //定义一个服务器使用的回调委托对象
        byte[] serverBuffer;             //数据缓存区  文字,音频,视频,图片...
    
        public void InitServer(MyCallBack callBack)
        {
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);  //参数(1.使用IP地址的类型 2.套接字类型,使用TCP的流式传输  3.使用TCP协议)
            serverBuffer = new byte[1024];    //初始化缓冲区的大小
            serverCallBack = callBack;        //绑定初始化服务器的回调方法
    
            IPEndPoint point = new IPEndPoint(IPAddress.Any, 34567);      //参数(1.地址,代表一台电脑, 2.端口号表示一个应用)
            serverSocket.Bind(point);    //绑定地址节点
            serverSocket.Listen(10);       //开始监听, 一旦监听成功,服务器就启动,10代表最大监听数量 
            serverCallBack("服务器启动成功");
    
            //服务器开始进入等待用户连接的状态
            //开辟一条子线程实时监测是否有人连接
            //一旦有客户端连接,立马通知主线程,通知内容会以IAsyncResult 返回,连接者的所有信息
            serverSocket.BeginAccept(ServerAccept, serverSocket);
        }
    
        //服务器开始接收的方法
        void ServerAccept(IAsyncResult ar)
        {
            serverSocket = ar.AsyncState as Socket;     //拿到当前连接服务器的Socket 对象
            Socket workingSocket = serverSocket.EndAccept(ar);         //将当前的Socket的全部信息交给一个新的Socket处理
    
            workingSocket.BeginReceive(serverBuffer, 0, serverBuffer.Length, SocketFlags.None,ServerReceive, workingSocket);  //(数据收发缓存区,起始位置,长度,不分类型,全部接收, 接受消息之后的回调,当前Socket的状态)
    
            serverSocket.BeginAccept(ServerAccept, serverSocket);      //尾递归
        }
        //服务器接收消息之后的回调方法
        void ServerReceive(IAsyncResult ar)
        {
            Socket workingSorket = ar.AsyncState as Socket;
            int size=workingSorket.EndReceive(ar);   //拿到接收到的数据一共有多少字节
            string str = Encoding.UTF8.GetString(serverBuffer);    //将接收到的byte数组转换成字符串
            serverCallBack("接收到了" + size + "字节");
            serverCallBack(str);       
            workingSorket.BeginReceive(serverBuffer, 0, serverBuffer.Length, SocketFlags.None, ServerReceive, workingSorket);   //尾递归
        }
        #endregion

     客户端代码

    #region
        Socket clientSocket;
        MyCallBack clientCallBack;
        byte[] clientBuffer;
        
        //客户端连接服务器的方法
        public void ClientConnectServer(string ip,int port,MyCallBack callBack)
        {
            clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            clientBuffer = new byte[1024];
            clientCallBack = callBack;
    
            clientSocket.Connect(IPAddress.Parse(ip),port);      //连接服务器
            clientCallBack("连接服务器成功");
            clientSocket.BeginReceive(clientBuffer, 0, clientBuffer.Length, SocketFlags.None,ClientReceive, clientSocket);
        }
    
        void ClientReceive(IAsyncResult ar)
        {
            Socket WorkingSocket = ar.AsyncState as Socket;
            int size=WorkingSocket.EndReceive(ar);   //接收多少字节
            string msg= Encoding.UTF8.GetString(clientBuffer);
            clientCallBack("接收了"+size+"字节");
            clientCallBack(msg);
            clientSocket.BeginReceive(clientBuffer, size, clientBuffer.Length, SocketFlags.None, ClientReceive, WorkingSocket);
        }
    
        //客户端发送消息的方法
        public void ClientSendMsg(string msg)
        {
            byte[] buffer= Encoding.UTF8.GetBytes(msg);
            clientSocket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, SendCallBack, clientSocket);
        }
        void SendCallBack(IAsyncResult ar)
        {
            Socket workingSocket = ar.AsyncState as Socket;
            workingSocket.EndSend(ar);
            clientCallBack("发送完成");
        }
    
    #endregion

    简单的Socket搭建完成,但是有一点小Bug,服务器进入等待用户连接状态后,会开辟子线程实时检测,没有关闭这条线程,因此在搭建服务器的脚本,可以在Start方法里写一个方法,在程序退出时关闭这条线程! 这个方法在关闭程序时自动调用

    private void OnApplicationQuit()
        {
            serverSocket.Shutdown(SocketShutdown.Both);
            serverSocket.Close();
        }

    简单的Socket搭建完了,当然这只是非常基础的Socket传递,在实际使用中,还要考虑很多问题,比如Socket的沾包, 闭包,需要进一步处理

  • 相关阅读:
    http协议详解(经典版)
    Sql语句清理日志文件
    Case when用法
    Sql Server 语句美化工具,SQL Pretty Printer Add-In for SSMS
    Ext.Net保存前判断GridPanel中必填项是否为空
    JavaScript中判断对象的值是否为undefined、null
    Your project specifies TypeScriptToolsVersion 3.1, but a matching compiler was not found. The latest available TypeScript compiler will be used (3.3). To remove this warning, install the TypeScript 3.
    gist.github.com 被墙无法访问解决办法
    VSCode 多标签打开文件
    VSCode安装与配置Eslint
  • 原文地址:https://www.cnblogs.com/dabaimifan/p/7215068.html
Copyright © 2011-2022 走看看