当前位置:   article > 正文

[C#实战][Unity实战].net + unity全栈代码 [V1:Framework+Unity] [V2:Netty+Core+Unity](Socket支持protobuf)_unity全栈 ta全栈

unity全栈 ta全栈

在这里插入图片描述.net有诸多版本,所以简单实现了Socket多线程的V1-Framework+Unity版本和V2-Core(Netty)+Unity版本

参考文档:

Siki学院-C#服务器
Azure-DotNetty

V1-Framework+Unity:GoogleProtoBuf/Log4Net

服务端

重点使用了Select{}这个特性
在这里插入图片描述

ServerSocket.cs

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Reflection;

namespace SimServer.Net
{
    public class ServerSocket : Singleton<ServerSocket>
    {
        //公钥
        public static string PublicKey = "DongServer_PublicKey";
        //密钥,后续可以随时间进行变化
        public static string SecretKey = "DongServer_SecretKey";

#if DEBUG
        private string m_IpStr = "127.0.0.1";
#else
        //对应阿里云或腾讯云的 本地ip地址(不是公共ip地址)
        private string m_IpStr = "172.45.756.54";
#endif
        private const int m_Port = 8011;

        public static long m_PingInterval = 30;

        //服务器监听socket
        private static Socket m_ListenSocket;

        //临时保存所有socket的集合
        private static List<Socket> m_CheckReadList = new List<Socket>();

        //所有客户端的一个字典
        public static Dictionary<Socket, ClientSocket> m_ClientDic = new Dictionary<Socket, ClientSocket>();

        public static List<ClientSocket> m_TempList = new List<ClientSocket>();

        public void Init() 
        {
            IPAddress ip = IPAddress.Parse(m_IpStr);
            IPEndPoint ipEndPoint = new IPEndPoint(ip, m_Port);
            m_ListenSocket = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            m_ListenSocket.Bind(ipEndPoint);
            m_ListenSocket.Listen(50000);

            Debug.LogInfo("服务器启动监听{0}成功", m_ListenSocket.LocalEndPoint.ToString());

            while (true) 
            {
                //检查是否有读取的socket

                //处理找出所有socket
                ResetCheckRead();

                try
                {
                    //最后等待时间单位是微妙
                    Socket.Select(m_CheckReadList, null, null, 1000);
                }
                catch (Exception e) 
                {
                    Debug.LogError(e.ToString());
                }

                for (int i = m_CheckReadList.Count - 1; i >= 0; i--)
                {
                    Socket s = m_CheckReadList[i];
                    if (s == m_ListenSocket)
                    {
                        //说明有客户端链接到服务器了,所以服务器socket可读
                        ReadListen(s);
                    }
                    else 
                    {
                        //说明链接的客户端可读,证明有信息传上来了
                        ReadClient(s);
                    }
                }

                //检测是否心跳包超时的计算


                long timeNow = GetTimeStamp();
                m_TempList.Clear();
                foreach (ClientSocket clientSocket in m_ClientDic.Values) 
                {
                    if (timeNow - clientSocket.LastPingTime > m_PingInterval * 4) 
                    {
                        Debug.Log("Ping Close" + clientSocket.Socket.RemoteEndPoint.ToString());
                        m_TempList.Add(clientSocket);
                    }
                }

                foreach (ClientSocket clientSocket in m_TempList)
                {
                    CloseClient(clientSocket);
                }
                m_TempList.Clear();
            }
        }

        public void ResetCheckRead() 
        {
            m_CheckReadList.Clear();
            m_CheckReadList.Add(m_ListenSocket);
            foreach (Socket s in m_ClientDic.Keys) 
            {
                m_CheckReadList.Add(s);
            }
        }

        void ReadListen(Socket listen) 
        {
            try
            {
                Socket client = listen.Accept();
                ClientSocket clientSocket = new ClientSocket();
                clientSocket.Socket = client;
                clientSocket.LastPingTime = GetTimeStamp();
                m_ClientDic.Add(client, clientSocket);
                Debug.Log("一个客户端链接:{0},当前{1}个客户端在线!",client.LocalEndPoint.ToString(),m_ClientDic.Count);
            }
            catch (SocketException ex)
            {
                Debug.LogError("Accept fali:" + ex.ToString());
            }
        }

        void ReadClient(Socket client) 
        {
            ClientSocket clientSocket = m_ClientDic[client];
            ByteArray readBuff = clientSocket.ReadBuff;
            //接受信息,根据信息解析协议,根据协议内容处理消息再下发到客户端
            int count = 0;
            //如果上一次接收数据刚好占满了1024的数组,
            if (readBuff.Remain <= 0) 
            {
                //数据移动到index =0 位置。
                OnReceiveData(clientSocket);
                readBuff.CheckAndMoveBytes();
                //保证到如果数据长度大于默认长度,扩充数据长度,保证信息的正常接收
                while (readBuff.Remain <= 0) 
                {
                    int expandSize = readBuff.Length < ByteArray.DEFAULT_SIZE ? ByteArray.DEFAULT_SIZE : readBuff.Length;
                    readBuff.ReSize(expandSize * 2);
                }
            }
            try
            {
                count = client.Receive(readBuff.Bytes, readBuff.WriteIdx, readBuff.Remain, 0);
            }
            catch (SocketException ex)
            {
                Debug.LogError("Receive fali:" + ex);
                CloseClient(clientSocket);
                return;
            }

            //代表客户端断开链接了
            if (count <= 0) 
            {
                CloseClient(clientSocket);
                return;
            }

            readBuff.WriteIdx += count;
            //解析我们的信息
            OnReceiveData(clientSocket);
            readBuff.CheckAndMoveBytes();
        }

        /// <summary>
        /// 接收数据处理
        /// </summary>
        /// <param name="clientSocket"></param>
        void OnReceiveData(ClientSocket clientSocket) 
        {
            ByteArray readbuff = clientSocket.ReadBuff;
            //基本消息长度判断
            if (readbuff.Length <= 4 || readbuff.ReadIdx < 0)
            {
                return;
            }
            int readIdx = readbuff.ReadIdx;
            byte[] bytes = readbuff.Bytes;
            int bodyLength = BitConverter.ToInt32(bytes, readIdx);
            //判断接收到的信息长度是否小于包体长度+包体头长度,如果小于,代表我们的信息不全,大于代表信息全了(有可能有粘包存在)
            if (readbuff.Length < bodyLength + 4) 
            {
                return;
            }
            readbuff.ReadIdx += 4;
            //解析协议名
            int nameCount = 0;
            ProtocolEnum proto = ProtocolEnum.None;
            try
            {
                proto = MsgBase.DecodeName(readbuff.Bytes, readbuff.ReadIdx, out nameCount);
            }
            catch (Exception ex) 
            {
                Debug.LogError("解析协议名出错:" + ex);
                CloseClient(clientSocket);
                return;
            }

            if (proto == ProtocolEnum.None) 
            {
                Debug.LogError("OnReceiveData MsgBase.DecodeName  fail");
                CloseClient(clientSocket);
                return;
            }

            readbuff.ReadIdx += nameCount;

            //解析协议体
            int bodyCount = bodyLength - nameCount;
            MsgBase msgBase = null;
            try
            {
                msgBase = MsgBase.Decode(proto, readbuff.Bytes, readbuff.ReadIdx, bodyCount);
                if (msgBase == null) 
                {
                    Debug.LogError("{0}协议内容解析错误:" ,proto.ToString());
                    CloseClient(clientSocket);
                    return;
                }
            }
            catch (Exception ex) 
            {
                Debug.LogError("接收数据协议内容解析错误:" + ex);
                CloseClient(clientSocket);
                return;
            }

            readbuff.ReadIdx += bodyCount;
            readbuff.CheckAndMoveBytes();
            //通过反射分发消息
            MethodInfo mi = typeof(MsgHandler).GetMethod(proto.ToString());
            object[] o = { clientSocket, msgBase };

            if (mi != null)
            {
                mi.Invoke(null, o);
            }
            else 
            {
                Debug.LogError("OnReceiveData Invoke fail:" + proto.ToString());
            }

            //继续读取消息
            if (readbuff.Length > 4) 
            {
                OnReceiveData(clientSocket);
            }
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="cs"></param>
        /// <param name="msgBase"></param>
        public static void Send(ClientSocket cs, MsgBase msgBase) 
        {
            if (cs == null || !cs.Socket.Connected)
            {
                return;
            }

            try 
            {
                //分为三部分,头:总协议长度;名字;协议内容。
                byte[] nameBytes = MsgBase.EncodeName(msgBase);
                byte[] bodyBytes = MsgBase.Encond(msgBase);
                int len = nameBytes.Length + bodyBytes.Length;
                byte[] byteHead = BitConverter.GetBytes(len);
                byte[] sendBytes = new byte[byteHead.Length + len];
                Array.Copy(byteHead, 0, sendBytes, 0, byteHead.Length);
                Array.Copy(nameBytes, 0, sendBytes, byteHead.Length, nameBytes.Length);
                Array.Copy(bodyBytes, 0, sendBytes, byteHead.Length + nameBytes.Length,bodyBytes.Length);
                try
                {
                    cs.Socket.BeginSend(sendBytes, 0, sendBytes.Length, 0, null, null);
                }
                catch(SocketException ex) 
                {
                    Debug.LogError("Socket BeginSend Error:" + ex);
                }
            }
            catch(SocketException ex) 
            {
                Debug.LogError("Socket发送数据失败:" + ex);
            }
        }

        public void CloseClient(ClientSocket client) 
        {
            client.Socket.Close();
            m_ClientDic.Remove(client.Socket);
            Debug.Log("一个客户端断开链接,当前总连接数:{0}", m_ClientDic.Count);
        }


        public static long GetTimeStamp() 
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds);
        }
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
Log4Net特殊配置问题:

log4net.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" type="System.Configuration.IgnoreSectionHandler"/>
  </configSections>
  <log4net>
    <root>
      <level value="All"/>
      <appender-ref ref="RollingLogFileAppender"/>
      <appender-ref ref="ConsoleAppender"/>
    </root>
          
    <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="log\logfile.log"/>
      <appendToFile value="true"/>
      <Encoding value="UTF-8" />
      <!--按日期产生文件夹,文件名[在日期方式与混合方式下使用]日志文件名格式为:2008-08-31.log -->
      <param name= "DatePattern" value= "yyyy-MM-dd&quot;.log&quot;"/>
      <!--log保留天数-->
      <param name= "MaxSizeRollBackups" value= "10"/>
      <!--日志文件名是否是固定不变的(是否只写到一个文件中)-->
      <param name= "StaticLogFileName" value= "false"/>
       <!--按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])-->
      <param name="RollingStyle" value="Date" />
      <!--每个文件的大小。只在混合方式与文件大小方式下使用,超出大小的在文件名后自动增加1重新命名-->
      <param name="maximumFileSize" value="500KB" />
      <layout type="log4net.Layout.PatternLayout">
         <!--
          %d, %date     :表示当然的时间
        %p, %level    :表示日志的级别
        %c, %logger   :表示日志产生的主题或名称,通常是所在的类名,便于定位问题
        %m, %message  :表示日志的具体内容
        %n, %newline  :换行
          %exception    :表示异常信息
        -->
       <param name="ConversionPattern" value="%d [%t] %-5p %c - %m %logger %n" />
      </layout>
    </appender>
  
    <!-- 控制台显示日志 -->
    <appender name="ConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
      <!-- 设置不同级别控制台显示的不同颜色 -->
      <mapping>
        <level value="INFO" />
        <foreColor value="Green" />
      </mapping>
      <mapping>
        <level value="DEBUG" />
        <foreColor value="White" />
      </mapping>
      <mapping>
        <level value="WARN" />
        <foreColor value="Yellow" />
      </mapping>
      <mapping>
        <level value="ERROR" />
        <foreColor value="Red, HighIntensity" />
      </mapping>
      <!-- 记录的格式。 -->
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date{HH:mm:ss,fff} [%-5level] %m %n" />
      </layout>
      <!-- 
      过滤器type有如下几种类型
      log4net.Filter.DenyAllFilter        丢弃所有日志事件。
      log4net.Filter.LevelMatchFilter      准确匹配事件等级。
      log4net.Filter.LevelRangeFilter      匹配一个范围的等级。
      log4net.Filter.LoggerMatchFilter    匹配一个日志器名字的开始。
      log4net.Filter.PropertyFilter        匹配指定属性名称的子字符串。
      log4net.Filter.StringMatchFilter    匹配事件消息的子字符串。
      -->
      <filter type="log4net.Filter.LevelRangeFilter">
        <!-- 控制输出日志的级别范围 -->
        <param name="LevelMin" value="DEBUG" />
        <param name="LevelMax" value="Error" />
      </filter>
    </appender>
  </log4net>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
  </startup>
</configuration>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82

设置始终复制

在这里插入图片描述
AssemblyInfo.cs增加代码使Log4Net生效

[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", ConfigFileExtension = "config", Watch = true)]
  • 1

在这里插入图片描述

客户端

在这里插入图片描述手写了一个ByteArray.cs(收发[]byte)

using System;

public class ByteArray
{
    //默认大小
    public const int DEFAULT_SIZE = 1024;
    //初始大小
    private int m_InitSize = 0;
    //缓冲区
    public byte[] Bytes;
    //读写位置, ReadIdx = 开始读的索引,WriteIdx = 已经写入的索引
    public int ReadIdx = 0;
    public int WriteIdx = 0;
    //容量
    private int Capacity = 0;

    //剩余空间
    public int Remain { get { return Capacity - WriteIdx; } }

    //数据长度
    public int Length { get { return WriteIdx - ReadIdx; } }

    public ByteArray()
    {
        Bytes = new byte[DEFAULT_SIZE];
        Capacity = DEFAULT_SIZE;
        m_InitSize = DEFAULT_SIZE;
        ReadIdx = 0;
        WriteIdx = 0;
    }

    public ByteArray(byte[] dafalutBytes) 
    {
        Bytes = dafalutBytes;
        Capacity = dafalutBytes.Length;
        m_InitSize = dafalutBytes.Length;
        ReadIdx = 0;
        WriteIdx = dafalutBytes.Length;
    }

    /// <summary>
    /// 检测并移动数据
    /// </summary>
    public void CheckAndMoveBytes()
    {
        if (Length < 8)
        {
            MoveBytes();
        }
    }

    /// <summary>
    /// 移动数据
    /// </summary>
    public void MoveBytes()
    {
        if (ReadIdx < 0)
            return;

        Array.Copy(Bytes, ReadIdx, Bytes, 0, Length);
        WriteIdx = Length;
        ReadIdx = 0;
    }

    /// <summary>
    /// 重设尺寸
    /// </summary>
    /// <param name="size"></param>
    public void ReSize(int size)
    {
        if (ReadIdx < 0) return;
        if (size < Length) return;
        if (size < m_InitSize) return;
        int n = 1024;
        while (n < size) n *= 2;
        Capacity = n;
        byte[] newBytes = new byte[Capacity];
        Array.Copy(Bytes, ReadIdx, newBytes, 0, Length);
        Bytes = newBytes;
        WriteIdx = Length;
        ReadIdx = 0;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84

MsgBase.cs 封装了proto加密解密

using ProtoBuf;
using System;
using System.IO;
using UnityEngine;

public class MsgBase
{
    public virtual ProtocolEnum ProtoType { get; set; }

    /// <summary>
    /// 编码协议名
    /// </summary>
    /// <param name="msgBase"></param>
    /// <returns></returns>
    public static byte[] EncodeName(MsgBase msgBase) 
    {
        byte[] nameBytes = System.Text.Encoding.UTF8.GetBytes(msgBase.ProtoType.ToString());
        Int16 len = (Int16)nameBytes.Length;
        byte[] bytes = new byte[2 + len];
        bytes[0] = (byte)(len % 256);
        bytes[1] = (byte)(len / 256);
        Array.Copy(nameBytes, 0, bytes, 2, len);
        return bytes;
    }

    /// <summary>
    /// 解码协议名
    /// </summary>
    /// <param name="bytes"></param>
    /// <returns></returns>
    public static ProtocolEnum DecodeName(byte[] bytes, int offset, out int count) 
    {
        count = 0;
        if (offset + 2 > bytes.Length) return ProtocolEnum.None;
        Int16 len = (Int16)((bytes[offset + 1] << 8) | bytes[offset]);
        if (offset + 2 + len > bytes.Length) return ProtocolEnum.None;
        count = 2 + len;
        try
        {
            string name = System.Text.Encoding.UTF8.GetString(bytes, offset + 2, len);
            return (ProtocolEnum)System.Enum.Parse(typeof(ProtocolEnum), name);
        }
        catch (Exception ex) 
        {
            Debug.LogError("不存在的协议:" + ex.ToString());
            return ProtocolEnum.None;
        }
    }

    /// <summary>
    /// 协议序列化及加密
    /// </summary>
    /// <param name="msgBase"></param>
    /// <returns></returns>
    public static byte[] Encode(MsgBase msgBase) 
    {
        using (var memory = new MemoryStream()) 
        {
            //将我们的协议类进行序列化转换成数组
            Serializer.Serialize(memory, msgBase);
            byte[] bytes = memory.ToArray();
            return bytes;
        }
    }

    /// <summary>
    /// 协议解密
    /// </summary>
    /// <param name="protocol"></param>
    /// <param name="bytes"></param>
    /// <param name="offset"></param>
    /// <param name="count"></param>
    /// <returns></returns>
    public static MsgBase Decode(ProtocolEnum protocol, byte[] bytes, int offset, int count) 
    {
        if (count <= 0)
        {
            Debug.LogError("协议解密出错,数据长度为0");
            return null;
        }
        try
        {
            byte[] newBytes = new byte[count];
            Array.Copy(bytes, offset, newBytes, 0, count);
            using (var memory = new MemoryStream(newBytes, 0, newBytes.Length)) 
            {
                Type t = System.Type.GetType(protocol.ToString());
                return (MsgBase)Serializer.NonGeneric.Deserialize(t, memory);
            }
        }
        catch(Exception ex) 
        {
            Debug.LogError("协议解密出错:" + ex.ToString());
            return null;
        }
    }
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99

V2-Core+Netty+Unity:GoogleProtoBuf/Serilog

服务端

netty中重点使用了ChannelRead
在这里插入图片描述

ServerHandler.cs

namespace TcpServer
{
    using System;
    using System.Linq;
    using System.Text;
    using DotNetty.Buffers;
    using DotNetty.Transport.Channels;

    public class EchoServerHandler : ChannelHandlerAdapter
    {
        public override void ChannelActive(IChannelHandlerContext context)
        {

        }
        public override void ChannelRead(IChannelHandlerContext context, object message)
        {
            var buffer = message as IByteBuffer;
            if (buffer != null)
            {
                Console.WriteLine("Received from client: " + buffer.ToString(Encoding.UTF8));
            }

            ReceiveFromClient(context, buffer);
        }

        public override void ChannelInactive(IChannelHandlerContext context)
        {
            context.CloseAsync();
        }
        public override void ChannelReadComplete(IChannelHandlerContext context)
        {
           //  => context.Flush();
        }

        public override void ExceptionCaught(IChannelHandlerContext context, Exception exception)
        {
            Console.WriteLine("Exception: " + exception);
            context.CloseAsync();
        }

        /// <summary>
        /// 发送客户端string
        /// </summary>
        /// <param name="context"></param>
        /// <param name="msg"></param>
        void SendToClient(IChannelHandlerContext context,string msg) {
            var buffer = ByteBufferUtil.EncodeString(ByteBufferUtil.DefaultAllocator,msg,Encoding.UTF8);
            if (buffer != null) {
                context.Channel.WriteAndFlushAsync(buffer);
                Debug.Instance.LogError("发送消息:" + msg.ToString());
            }
        }

        /// <summary>
        /// 发送消息 MsgTest data = new MsgTest();data.RecContent = "这是1个Server回复";
        /// </summary>
        /// <param name="context"></param>
        /// <param name="msg"></param>
        void SendToClient(IChannelHandlerContext context, MsgBase msg)
        {
            byte[] nameBytes = MsgBase.EncodeName(msg);
            byte[] bodyBytes = MsgBase.Encode(msg);
            byte[] dataBuff = nameBytes.Concat(bodyBytes).ToArray();

            IByteBuffer buffer = Unpooled.WrappedBuffer(dataBuff);
            context.Channel.WriteAndFlushAsync(buffer);
            Debug.Instance.LogError("发送消息:"+msg.ToString());
        }

        void ReceiveFromClient(IChannelHandlerContext context, IByteBuffer buffer) {
            byte[] bytes = new byte[buffer.ReadableBytes];
            buffer.ReadBytes(bytes);

            int nameCount = 0;
            int readIdx = 0;
            ProtocolEnum protocol = MsgBase.DecodeName(bytes, readIdx, out nameCount);
            if (protocol == ProtocolEnum.None)
            {
                string s = buffer.ToString(Encoding.UTF8);
                Debug.Instance.LogError("收到消息:"+s);
                Debug.Instance.LogError("ReceiveFromClient DecodeName Fail");
                context.CloseAsync();
                return;
            }

            readIdx += nameCount;
            MsgBase msgBase = MsgBase.Decode(protocol, bytes, readIdx, bytes.Length - readIdx);
            if (msgBase == null)
            {
                Debug.Instance.LogError("ReceiveFromClient Decode Fail");
                context.CloseAsync();
                return;
            }

            if (msgBase is MsgCSharp)
            {
                var msg = msgBase as MsgCSharp;
                msg.RecContent = "我是3!-server";
                SendToClient(context, msgBase);
            }
            else if (msgBase is MsgLua)
            {
                var msg = msgBase as MsgLua;
                Debug.Instance.Log(msg.LuaJson);
            }
            else { 
                // TODO 其他类型支持
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111

客户端

因为Netty配置的大小端问题,我统一设置为小端,处理Unity相关的与V1有部分不同
在这里插入图片描述

发消息:
public void SendMessage(MsgBase msgBase) 
    {
        if (m_Socket == null || !m_Socket.Connected) 
        {
            return;
        }

        if (m_Connecting) 
        {
            Debug.LogError("正在链接服务器中,无法发送消息!");
            return;
        }

        if (m_Closing) 
        {
            Debug.LogError("正在关闭链接中,无法发送消息!");
            return;
        }

        try
        {
            byte[] nameBytes = MsgBase.EncodeName(msgBase);
            byte[] bodyBytes = MsgBase.Encode(msgBase);
            byte[] dataBuff = nameBytes.Concat(bodyBytes).ToArray();

            byte[] lenBuff = BitConverter.GetBytes((ushort) dataBuff.Length);
            if (!BitConverter.IsLittleEndian)
            {
                lenBuff.Reverse();
            }
            byte[] sendBytes = lenBuff.Concat(dataBuff).ToArray();
            ByteArray ba = new ByteArray(sendBytes);
            
            int count = 0;
            lock (m_WriteQueue) 
            {
                m_WriteQueue.Enqueue(ba);
                count = m_WriteQueue.Count;
            }

            if (count == 1) 
            {
                m_Socket.BeginSend(sendBytes, 0, sendBytes.Length, 0, SendCallBack, m_Socket);
            }
        }
        catch (Exception ex) 
        {
            Debug.LogError("SendMessage error:" + ex.ToString());
            Close();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
收消息:
void OnReceiveData() 
    {
        if (m_ReadBuff.Length <= 2 || m_ReadBuff.ReadIdx < 0)
            return;
        
        int readIdx = m_ReadBuff.ReadIdx;
        byte[] bytes = m_ReadBuff.Bytes;
        
        //读取协议长度之后进行判断,如果消息长度小于读出来的消息长度,证明是没有一条完整的数据
        int bodyLength = BitConverter.ToUInt16(bytes, readIdx);
        if (m_ReadBuff.Length < bodyLength + 2) 
        {
            return;
        }

        string msg = Encoding.UTF8.GetString(m_ReadBuff.Bytes, 2, m_ReadBuff.WriteIdx);
        Debug.LogError("收到数据:"+msg);

        m_ReadBuff.ReadIdx += 2;
        int nameCount = 0;
        ProtocolEnum protocol = MsgBase.DecodeName(m_ReadBuff.Bytes, m_ReadBuff.ReadIdx, out nameCount);
        if (protocol == ProtocolEnum.None) 
        {
            Debug.LogError("OnReceiveData MsgBase.DecodeName fail");
            Close();
            return;
        }

        m_ReadBuff.ReadIdx += nameCount;
        //解析协议体
        int bodyCount = bodyLength - nameCount;
        try
        {
            MsgBase msgBase = MsgBase.Decode(protocol, m_ReadBuff.Bytes, m_ReadBuff.ReadIdx, bodyCount);
            if (msgBase == null) 
            {
                Debug.LogError("接受数据协议内容解析出错");
                Close();
                return;
            }
            m_ReadBuff.ReadIdx += bodyCount;
            m_ReadBuff.CheckAndMoveBytes();
            //协议具体的操作
            lock (m_MsgList) 
            {
                m_MsgList.Add(msgBase);
                Debug.Log(msgBase.ToString());
            }
            m_MsgCount++;
            //处理粘包
            if (m_ReadBuff.Length > 2) 
            {
                OnReceiveData();
            }
        }
        catch (Exception ex) 
        {
            Debug.LogError("Socket OnReceiveData error:" + ex.ToString());
            Close();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

我的实现:

github

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/117977
推荐阅读
相关标签
  

闽ICP备14008679号