• Unity3d在线游戏Socket通讯


    网络游戏是一个人的互动娱乐软件应用。因为它是交互式,当然,需要了解对方的通信。这需要通信Socket:我们今天要实现的主角即套接字。Socket的英文原义是“孔”或“插座”。正如其英文原意那样。象一个多孔插座。

    一台电脑机器宛如布满各种插座的房间,每一个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电。有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就能够得到不同的服务。以下我们来看看下图,游戏中玩家移动是怎样通讯:


    以下是Unity3d游戏通讯Socket实现: BaseGameSocket.cs

    //@原创:dongfu.luo
    using System;
    using System.Collections.Generic;
    using System.Net.Sockets;
    public abstract class BaseGameSocket
    {
        //用来接收服务端发过来的缓冲Buff
        private byte[] _data_buffer;
    
      //缓冲二进制数组从哪里開始读
        private int _data_offset;
    
    //缓冲二进制数组读多少个byte
        private int _data_size;
    
    //游戏serverIP地址
        private string _ip;
        private bool _is_read_head;
    
    //游戏server端口
        private int _port;
    
    //要服务端发送的数据命令列表
        private List<PacketOut> _send_list = new List<PacketOut>();
        private Socket _sock;
        private const int MAX_SEND_QUEUE = 0x3e8;
    
    //清空数据,通常是在断开重联时候调用 
        private void Clear()
        {
            this._ip = null;
            this._port = 0;
            this._sock = null;
            List<PacketOut> list = this._send_list;
            lock (list)
            {
                this._send_list.Clear();
            }
            this._is_read_head = false;
            this._data_buffer = null;
            this._data_offset = 0;
            this._data_size = 0;
        }
    
    //关闭client的Socket 
        public void Close()
        {
     try
            {
                Socket socket = this._sock;
                this.Clear();
                if ((socket != null) && socket.Connected)
                {
                    socket.Shutdown(SocketShutdown.Both);
                    socket.Close();
                }
            }
            catch (Exception exception)
            {
                UEDebug.LogError("Connect: " + exception.ToString());
                this.Error(Lang.GetString("k3432"));
            }
        }
    
     //连接游戏服务端
    public void Connect(string ip, int port)
        {
            try
            {
                this.Close();
                this._ip = ip;
                this._port = port;
                this._sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                this._sock.NoDelay = true;
                this._sock.BeginConnect(this._ip, this._port, new AsyncCallback(this.OnConnect), this._sock);
            }
            catch (Exception exception)
            {
                UEDebug.LogError("Connect: " + exception.ToString());
                this.Error(Lang.GetString("k3432"));
            }
        }
    
    //假设Socket没有关闭继续等server信息,假设有信息则開始读 
        private void ContinueRead()
        {
            try
            {
                if (this.IsConnected)
                {
    this._sock.BeginReceive(this._data_buffer, this._data_offset, this._data_size - this._data_offset, SocketFlags.None, new AsyncCallback(this.OnRead), null);
                }
            }
            catch (Exception exception)
            {
                UEDebug.LogError(exception.ToString());
                this.Error(Lang.GetString("k3432"));
            }
        }
    
    
    //从发送队列从不断向游戏server发送命令 
        private void ContinueSend()
        {
            PacketOut state = null;
            List<PacketOut> list = this._send_list;
     lock (list)
            {
                if (this._send_list.Count == 0)
                {
                    return;
                }
                state = this._send_list[0];
                if (state.start)
                {
                    return;
                }
                state.start = true;
            }
            Socket sock = state.sock;
            if (sock.Connected)
            {
                sock.BeginSend(state.buff, 0, state.buff.Length, SocketFlags.None, new AsyncCallback(this.OnSend), state);
            }
        }
    //发送失败或错误,则关闭Socket通常是网络断了server关闭了 
        protected void Error(string msg)
        {
            this.Close();
            this.OnError(msg);
        }
    
    //程序员都知道这是析构函数 
        ~PackedSocket()
        {
            this.Close();
        }
        public int GetSendQueueSize()
        {
            List<PacketOut> list = this._send_list;
            lock (list)
            {
                return this._send_list.Count;
            }
        }
    
    //此函数由子类去处理 
        protected abstract void OnConnect();
    
    //假设是第一次连接上了,解析消息头
        private void OnConnect(IAsyncResult ret)
        {
            if (ret.AsyncState == this._sock)
            {
                try
                {
                    this._sock.EndConnect(ret);
                    this.ReadHead();
                    this.OnConnect();
                }
                catch (Exception exception)
                {
                      Debug.log(exception);
                 }
            }
        }
        protected abstract void OnError(string msg);
        protected abstract void OnPack(byte[] data);
    
    //有服务端信息来,開始解析,现解析信息头再解析消息体
        private void OnRead(IAsyncResult ar)
        {
            try
            {
                if (this.IsConnected)
                {
                    int num = this._sock.EndReceive(ar);
                    this._data_offset += num;
                    if (num <= 0)
                    {
                        
                    }
                    else if (this._data_offset != this._data_size)
                    {
                        this.ContinueRead();
                    }
                    else if (this._is_read_head)
                    {
     int num2 = BitConverter.ToInt32(this._data_buffer, 0);
                        this.ReadData(num2);
                    }
                    else
                    {
                        this.OnPack(this._data_buffer);
                        this.ReadHead();
                    }
                }
            }
            catch (Exception exception)
            {
          Debug.log(exception);
           }
        }
    
    //假设命令发送成功。检查发送队列是否还有须要发送的命令。

    假设有则继续发送 private void OnSend(IAsyncResult ar) { PacketOut asyncState = ar.AsyncState as PacketOut; Socket sock = asyncState.sock; if (sock.Connected) { sock.EndSend(ar); List<PacketOut> list = this._send_list; lock (list) { if (this._send_list.Contains(asyncState)) { this._send_list.Remove(asyncState); } } this.ContinueSend(); } } //读取消息体 private void ReadData(int pack_len) { this._is_read_head = false; this._data_size = pack_len; this._data_offset = 4; this._data_buffer = new byte[this._data_size]; this.ContinueRead(); } //读取消息头 private void ReadHead() { this._is_read_head = true; this._data_size = 4; this._data_offset = 0; this._data_buffer = new byte[this._data_size]; this.ContinueRead(); } //详细的发送信息,先把数据发到发送队列 public void Send(byte[] buff) { if (this.IsConnected) { PacketOut item = new PacketOut { start = false, buff = buff, sock = this._sock }; int count = 0; List<PacketOut> list = this._send_list; lock (list) { this._send_list.Add(item); count = this._send_list.Count; } if (count > 0x3e8) { } else { this.ContinueSend(); } } } public bool IsClosed { get { return (this._sock == null); } } public bool IsConnected { get { return ((this._sock != null) && this._sock.Connected); } } private class PacketOut { public byte[] buff; public Socket sock; public bool start; } }



  • 相关阅读:
    【超分辨率】—基于深度学习的图像超分辨率最新进展与趋势
    【超分辨率】—超分辨率补充问题
    随机采样一致算法RANSAC
    【相机篇】从到FlyCapture2到Spinnaker
    【超分辨率】—(ESRGAN)增强型超分辨率生成对抗网络-解读与实现
    AI佳作解读系列(六) - 生成对抗网络(GAN)综述精华
    AI佳作解读系列(五) - 目标检测二十年技术综述
    TroubleShooting经验总结
    读书笔记 - 《深度学习之美》(更新中...)
    深度学习中那些有趣的定理或理论
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4649585.html
Copyright © 2020-2023  润新知