zoukankan      html  css  js  c++  java
  • 网络游戏的前后端通讯(二)

    【旧博客转移 - 2015年9月20日 22:48】

    1.Socket的粘包拆包

    tcp协议是有缓冲区的,如果发送的数据太小,会被放置缓冲区里,累积更多的数据再一起发送,发送后不会立马清除缓冲区,等待TCP应答消息到了,才会清除缓冲区。没应答就会继续重发,造成粘包的原因有几种。
    1. 发送端的多个数据包在缓冲区里一起发送
    2. 接收端由于网络原因阻塞,然后一次性接受多个包
    另外数据包大小比缓冲区大小大的话,会被分成多个片分开发送。
    解决以上问题,可以在包的结构设计上处理,一般都采用 包头(4字节)+数据 的结构来封包,包头写入包的长度,下面请看解析包代码
    /**
     * 封包
     * **/
    private void send(Message vo){
        if(vo == null)return;
        MemoryStream buff = new MemoryStream();
        byte[] voByte = Message.encode(vo);
        byte[] pLen = ByteArrayUtil.writeInt(voByte.Length);
        buff.Write(pLen, 0, 4);//写包头
        buff.Write(voByte, 0, voByte.Length);
        _socket.Send(buff.ToArray());
    }
    //开一个子线程接受数据
    class SocketThread
    {
        public Connection conn;
    
        private int len = 0;
        public void run(){
            while(true){
                if(conn.state != Connection.CONNECTED)continue;
                if(len == 0){
                    if(conn._socket.Available < 4)continue;//不足4字节读包长
                    byte[] lenB = new byte[4];
                    conn._socket.Receive(lenB, 4, SocketFlags.None);
                    len = ByteArrayUtil.readInt(lenB);//读出包长
                }
                if(conn._socket.Available < len) continue;//不足一个包
    
                byte[] voB = new byte[len];
                conn._socket.Receive(voB, len, SocketFlags.None);//把包读出来
    
                len = 0;
    
                MemoryStream ms = new MemoryStream(voB);
                Message vo = Message.decode(ms);//解码包
                ms.Close();
                Debug.Log("receive:"+vo.getClassName());
                conn.resultConnectionHandler(vo);
            }
        }
    }

    2.协议加密校验

    很多游戏的数据都是明文传输的,别人使用一些抓包工具如Wireshark、WPE等等,就可以轻易修改网络包数据。为了防止数据被修改,我们可以做一下校验,这里介绍一种简单的加key校验方法,服务端跟客户端都用同一种校验算法,根据key生成一个校验值,然后在数据中把这个校验值传输给前端,前端再做校验判断
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace test
    {
        class Program
        {
    
            private byte[] datas = new byte[100];
    
            public Program() {
    
                //随机生成100个字节的测试数据
                Random random = new Random();
                for (int i = 0; i < datas.Length; i++)
                {
                    datas[i] = (byte)random.Next(1, 255);
                }
    
                ArrayToString(datas);//打印数组
    
                //校验密钥
                int key = 109;
    
                int checkVal = CheckBytes(datas, key);//生成校验值
                Console.WriteLine("校验值:" + checkVal);
    
                datas[3] = 2;//模拟抓包工具修改数值
    
                Console.WriteLine("模拟抓包工具修改数值:");
    
                ArrayToString(datas);//打印数组
    
                int checkVal2 = CheckBytes(datas, key);//再次生成校验值,此时数据已经在上面被模拟修改了
                Console.WriteLine("校验值:" + checkVal2);
    
                if (checkVal != checkVal2)
                {
                    Console.WriteLine("检测到被修改的数据包!");
                }
    
            }
    
            ///
         /// <summary>
            /// 根据key校验字节数组
            /// </summary>
    
            public int CheckBytes(byte[] datas, int key)
            {
                int sumCalc = 0;
                int i = datas.Length;
                //每一个字节都会影响校验值
                while(--i > -1)
                {
                    sumCalc += (int)(datas[i] ^ key >> datas[i]);
                }
                return sumCalc;
            }
    
            public void ArrayToString(byte[] datas)
            {
                string str = "";
                for (int i = 0; i < datas.Length; i++)
                {
                    str += datas[i] + ",";
                }
                Console.WriteLine(str.Substring(0, str.Length-1));
            }
    
            static void Main(string[] args)
            {
                new Program();
    
                Console.ReadKey();
            }
    
        }
    }

    运行结果:

    不过如果你的客户端代码被别人反编译了,别人知道了怎么获取key以及校验算法后,就能把值修改成能校验通过的数据,所以怎么隐藏key很重要,客户端代码加密混淆也很重要。

  • 相关阅读:
    自定义组件要加@click方法
    绑定样式
    647. Palindromic Substrings
    215. Kth Largest Element in an Array
    448. Find All Numbers Disappeared in an Array
    287. Find the Duplicate Number
    283. Move Zeroes
    234. Palindrome Linked List
    202. Happy Number
    217. Contains Duplicate
  • 原文地址:https://www.cnblogs.com/lijiajia/p/6861282.html
Copyright © 2011-2022 走看看