蛙蛙教你解析网络包

摘要:做网络应用,封包,解包是家常便饭,但如何做到准确、稳定而且性能好,却不太容易做到,这次和大家分享一下我在解析网络包上的经验。

思路:设计一个网络协议,一般都会分包,一个包就相当于一个逻辑上的命令。
1、如果我们用udp协议,省事的多,一次会收到一个完整的包,但UDP不可靠,顺序也不能保证,当然像QQ对UDP封装的很好,模拟了TCP的可靠性。网上也有一些封装好的可靠的UDP组件,大家用的话可以找找。关于用什么协议好这个问题,本贴不讨论。
2、如果我们用TCP协议不是长连接,像HTTP(不考虑KeepAlive)那样,一个连接上只发送一个包,我们也会很清晰的区分出接受到的每一个包。
3、还有就是我们还用TCP长连接,但每次发送固定长度的包,如果要发送的数据长度不够就用/0补齐,如果大于固定长度,就分成几个发,这个也很简单实用。
4、再有就是一个包有特定的开始和结尾,比如包头是<bof>包尾是<eof>,我们在可以从头读到尾,并把一个一个的包放入队列,由处理线程去处理。
5、再有一种就是每个包有固定长度的header,这个header里包含一个包的长度信息,我们可以先从头里读出长度信息,然后再借着读这么长的数据,完了这就是一个包。

关于封包的几种类型我就想到这么多,其中的利弊大家一看便知,我就不忽悠了,本文主要介绍最后一种方式,好多网络协议用的都是这种,包括CMPP协议,我们自己设计协议的时候一般不用像CMPP协议那样,因为二进制协议虽然虽然节省网络流量,但可读性不好。出问题,抓个包分析起来太麻烦。我们可以用.net自带的序列功能把要发送的类序列化成XML字符串发送出去,这多好看呀。

由于Socket缓冲区设置及其他的原因,Socket在接受数据的时候有时候不能完整的收到一个包,就是你读出包的长度后,可能不能一次就读取这么多数据。而如果读个半截儿的包就用UTF8Encoding等来解析,会解析出乱码的,我们这里用Encoding.UTF8.GetDecoder()来对包进行成块儿的解析,它就是用来做这种事情的。

下面就来看一下代码,代码的注释很全,演示了一个包从发到接受、解析的全过程,其中接受的过程没有一次收全所有的包,而是收了好几次,但我们最终还是成功的解析了收到的包。

public static void UnPack()
{
    //1、声明通过socket发送的字符串
    string toSendStringBySocket = "娃娃士大夫%#¥%My name is 蛙蛙王子!!";
    //2、转换成utf-8字节数组
    byte[] bsInput = Encoding.UTF8.GetBytes(toSendStringBySocket);

    //3、计算要发送的字节数组的长度,并写到第一块儿字节数组的开头
    //一般协议设计里都有一个长度的Header,这里就是写这个Header
    int inputBytesCount = bsInput.Length;
    byte[] bs1 = new byte[4 + 3]; //4是一个int的长度,3是底一块字节数组除了Header剩余的大小
    Buffer.BlockCopy(BitConverter.GetBytes(inputBytesCount), 0, bs1, 0, 4);

    //4、把要发送的字节数组拆分成3块儿发出去,因为socket在接受字节数组的时候
    //也可能半截半截儿的接收,我们就是要模拟这种效果下的拆包,因为第一块包写了
    //一个4个字节的Header,而第一块字节数组长度是7,所以再写三个字节长度的数据
    int offSet = 0;
    Buffer.BlockCopy(bsInput, offSet, bs1, 4, 3);
    offSet += bs1.Length - 4;

    //5、写第二块儿数据
    byte[] bs2 = new byte[8];
    Buffer.BlockCopy(bsInput, offSet, bs2, 0, bs2.Length);
    offSet += bs2.Length;

    //6、写第三块儿数据,我们这里模拟在最后一块数据的末尾加一些乱七八糟的数据
    //这些乱七八糟的数据有可能是下一个包的header。
    byte[] bs3 = new byte[bsInput.Length - offSet + 4];
    Buffer.BlockCopy(bsInput, offSet, bs3, 0, bsInput.Length - offSet);
    Buffer.BlockCopy(new byte[] { 1, 2, 3, 4 }, 0, bs3, bs3.Length - 4, 4);

    //7、Socket的接收方在执行BeginReceive函数,并回调函数里把收到的数据放入一个队列里
    //dotNet的队列内部就是一个环形数组,这里直接就当环形缓冲区来用了。
    Queue<byte[]> bufferPool = new Queue<byte[]>();
    bufferPool.Enqueue(bs1);
    bufferPool.Enqueue(bs2);
    bufferPool.Enqueue(bs3);

    //8、初始化一些变量准备解包
    
    //声明一个字符串缓冲区,大小是你的协议里规定的最大的包体长度
    char[] chars = new char[256]; 
    //定义一个UTF-8的Decoder,它可以成块的解包,内部自动维护解析状态
    //关于它的使用请参考MSDN或者《.net框架设计》
    Decoder d = Encoding.UTF8.GetDecoder();
    int charLen = 0; //定义每次解包返回的字符长度
    int parseBytesCount = 0;  //定义已解包的字节数
    int LenghHeader = 0; //定义收到包的长度
    bool needReadLengthHeader = true; //是否需要读取长度的头

    int srcOffSet = 0; //定义要解析的数据块的偏移量
    byte[] tempBuffer;
    //9、当环形缓冲里有数据的时候就一直解析
    while (bufferPool.Count > 0)
    {
        //10、读取数据包的长度信息,LengthHeader
        //因为第一块儿包包含长度信息,所以要先读出来
        //读了长度包后,要把数据库解析偏移量加4
        if(needReadLengthHeader)
        {
            LenghHeader = BitConverter.ToInt32(bs1, parseBytesCount);
            needReadLengthHeader = false;
            srcOffSet = 4;
        }
        
        //11、从环形缓冲区取出一块儿数据
        tempBuffer = bufferPool.Dequeue();
        parseBytesCount += tempBuffer.Length-srcOffSet; //更改已解析的字节数

        //12、如果已解析的字节数大于数据的长度,那么只解需要解析的字节
        if (parseBytesCount > LenghHeader)
        {
            parseBytesCount -= tempBuffer.Length;
            d.GetChars(tempBuffer, srcOffSet, inputBytesCount - parseBytesCount, chars, charLen);
            //这里记录下当前的临时缓冲区已解析到了什么位置,准备解析下一个包
            srcOffSet = inputBytesCount - parseBytesCount; //
            break;
        }
        //13、解析这半拉包
        charLen += d.GetChars(tempBuffer, srcOffSet, tempBuffer.Length-srcOffSet, chars, charLen);
        srcOffSet = 0;
    }

    string s = new string(chars);
    //14、通知包处理线程来处理这个包
    Console.WriteLine(s); 
}

蛙蛙推荐:蛙蛙教你解析网络包相关推荐

  1. wireshark帮你解析网络包

    1.下载安装 windows下载安装,选择你需要的版本. https://www.wireshark.org/download.html 2.如何开始捕获分组 点击鲨鱼鳍开始,一切都从开始开始. 点击 ...

  2. 蛙蛙推荐:蛙蛙教你文本聚类 - 蛙蛙王子 - 博客园

    蛙蛙推荐:蛙蛙教你文本聚类 - 蛙蛙王子 - 博客园 蛙蛙推荐:蛙蛙教你文本聚类 - 蛙蛙王子 - 博客园 蛙蛙推荐:蛙蛙教你文本聚类 摘要:文本聚类是搜索引擎和语义web的基本技术,这次本蛙和大家一 ...

  3. 蛙蛙推荐:蛙蛙教你文本聚类

    蛙蛙推荐:蛙蛙教你文本聚类 摘要:文本聚类是搜索引擎和语义web的基本技术,这次本蛙和大家一起学习一下简单的文本聚类算法,可能不能直接用于实际应用中,但对于想学搜索技术的初学者还是有一定入门作用的.这 ...

  4. 蛙蛙推荐:蛙蛙牌网页捕捉器

    蛙蛙推荐:蛙蛙牌网页捕捉器 摘要:你有没有看到一篇好文章想保存到本地,有没有想过只保存网页选中的部分而不要那些不必要的导航和广告,本贴告诉你达到这个目的的思路及主要代码. 思路:首先我们要获取到所有I ...

  5. 蛙蛙推荐:蛙蛙浏览器

    蛙蛙推荐:蛙蛙浏览器 摘要:google推出了自己的网页浏览器,现在web浏览器的竞争更激烈了,各有各的用户群.其实有另一个领域没有多少竞争,那就是应用程序浏览器,今天给大家演示的蛙蛙浏览器,不仅可以 ...

  6. 蛙蛙推荐:蛙蛙牌软件注册码算法

    蛙蛙推荐:蛙蛙牌软件注册码算法 摘要:辛辛苦苦写个共享软件,又怕被人破解,所以就会想到用注册码的方式来激活软件.本蛙给大家一个简单的思路来实现软件注册码算法,当然.net做的东西很容易被人破解,反编译 ...

  7. python编程例子 输入 输出-推荐 :手把手教你用Python创建简单的神经网络(附代码)...

    原标题:推荐 :手把手教你用Python创建简单的神经网络(附代码) 作者:Michael J.Garbade:翻译:陈之炎:校对:丁楠雅 本文共2000字,9分钟. 本文将为你演示如何创建一个神经网 ...

  8. windows下手把手教你捕获数据包

    希望通过这一系列的文章,能使得关于数据包的知识得以普及,所以这系列的每一篇文章我都会有由浅入深的解释.详细的分析.以及编码步骤,另外附上带有详细注释的源码 文章作者:nirvana 经常看到论坛有人问 ...

  9. 手把手教你捕获数据包

    原文链接:http://blog.csdn.net/piggyxp/article/details/24444 前   言 经常看到论坛有人问起关于数据包的截获.分析等问题,幸好本人也对此略有所知,也 ...

最新文章

  1. 20131003国庆作业例4-4,4-5,4-6.
  2. springboot-springmvc请求参数获取与原理【长文预警,收藏慢啃】
  3. 2018计算机领域大事件,吕伟:2018年计算机行业回顾
  4. c语言修改elf文件crc32,ELF文件中调试信息的格式说明?
  5. SAP CRM WebClient UI F4 value help is centrally implemented in CRM_THTMLB_UTIL/F4Frameset.html
  6. 贴一下目前的工作任务列表
  7. 前魅族副总裁李楠上手魅族17:颜值提升了
  8. jq php上传图片插件,ajaxImageUpload
  9. Python 进阶:全面解读高级特性之切片!
  10. QT 实现采集即时音频信号并发送至另一台电脑播放
  11. 央视推荐的护眼台灯是什么牌子?教育照明灯具品牌
  12. lighttpd服务器搭建教程
  13. 围观神仙打架,反革命工程师《iOS应用架构谈 组件化方案》和蘑菇街Limboy的《蘑菇街 App 的组件化之路》的阅读指导
  14. 作为SLAM中最常用的闭环检测方法,视觉词袋模型技术详解来了
  15. vue实现页面跳转过渡效果 transition
  16. [经验]2020届后台开发方向实习,秋招经验总结
  17. 下单账户与实付账户不一致_如何保护您的不一致帐户
  18. 排列 组合 算法(一)
  19. 公有云与私有云的区别(转)
  20. 诺基亚Lumia630传感器并未缩水

热门文章

  1. 乐鑫esp8266学习rtos3.0笔记第3篇: 一篇文章带你搞掂存储技术 NVS 的认识和使用,如何利用NVS保存整型、字符串、数组以及结构体。(附带demo)
  2. 如何将m4a格式音频转为mp3?
  3. 各种范文都有,到时不用找了。(值得收藏)
  4. 触摸屏中应用的电容式触摸芯片
  5. 基于机器视觉的机器人智能制造实践应用研究
  6. 微信小程序开发笔记(一)
  7. 平台如何实现实人认证?
  8. Consul作为配置中心,配置Asp.Net Core应用程序 依据key/value动态更新
  9. 谷歌表格_如何计算Google表格中的空白或空单元格
  10. 您真的会用百度吗?(百度搜索技巧-超详细)