`
bjxagu
  • 浏览: 165349 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

解析网络包

阅读更多

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

思路:设计一个网络协议,一般都会分包,一个包就相当于一个逻辑上的命令。
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, 04);

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

    int offSet = 0;
    Buffer.BlockCopy(bsInput, offSet, bs1, 
43
);
    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[] 1234 }0, bs3, bs3.Length - 44
);

    
//
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); 
}
分享到:
评论

相关推荐

    自己编写的简单网络协议解析器,用于抓包并解析数据包

    在抓包的同时解析数据包(不能等抓包停止后才解析),可判断IP、TCP或UDP数据包的校验和是否正确;支持BPF过滤器,抓包过程可以暂停和停止;可将数据包存储在pcap文件中,以供wireshark或其它数据包解析工具分析;可以...

    java抓包、解析

    Java抓包与解析是网络通信分析中的关键技术,它允许开发者获取网络数据包并进行深入分析。这个项目结合了两个代码示例,展示了如何在Java环境中实现这一功能。下面将详细介绍这个领域的相关知识点。 1. **Java抓包...

    解析ARP数据包含C++源码

    本资源提供了一个计算机网络课程设计项目,旨在解析ARP数据包,包含C++源码。该项目要求使用Visual C++ 6.0开发,能够直接运行出结果。 知识点1:ARP协议的消息格式 ARP协议的消息格式是指ARP数据包的结构,它由...

    java应用开发解析包

    在Java应用开发中,解析包通常包含了用于处理数据解析、网络通信和数据库操作的重要库和工具。本资源集合涵盖了MySQL数据库交互、JSON数据格式处理以及HTTP网络请求等多个关键领域,对于提升Java开发者的工作效率和...

    ARP补包和解析工具(计算机网络课程设计)

    计算机网络的课程设计,是一个ARP补包和解析的DOS窗口工具,每句代码都有解析,非常实用的东西,使用前要到处wndpack开发包,安装一下winpcap,然后就根据里面的实验文档就可以使用啦~ 希望能给学习计算机网络的同学...

    在MFC中ARP包的解析实例,包含相关文档

    在MFC(Microsoft Foundation Classes)框架中解析ARP(Address Resolution Protocol)包是一项常见的网络编程任务,主要用于处理局域网内的地址解析。ARP是TCP/IP协议栈中的一个关键部分,它负责将IP地址映射到物理...

    利用WipCap捕获网络数据包并分析数据包,含源代码和工程文件,学习网络数据包捕获分析以及WinPcap的好程序

    1. 数据包解析:WipCap支持多种网络协议的解析,包括TCP/IP、ARP、ICMP等。解析过程通常涉及提取每个协议层的头部信息,如源/目标IP地址、端口号、序列号等。 2. 内容分析:通过解析得到的信息,我们可以深入了解...

    燕山大学计算机网络三级项目

    在这个项目中,学生可能需要编写程序来实现这些功能,例如使用编程语言如Python、C++或Java来捕获和解析网络包。他们可能需要利用网络编程库,如libpcap或Python的Scapy库,来拦截、分析和显示IP数据报的详细信息。 ...

    解析pcap包工具

    标题中的“解析pcap包工具”指的是用于处理网络封包捕获(packet capture)文件的软件,这类工具能够分析和解读网络数据传输过程中的详细信息。在IT领域,pcap(Packet Capture)文件通常用于网络故障排查、安全审计...

    pcap4j 实现本地抓包以及解析DNS

    在标题“pcap4j 实现本地抓包以及解析DNS”中,我们关注的核心知识点是使用Pcap4J进行本地网络数据包的抓取以及DNS(Domain Name System)解析的过程。 首先,我们要理解什么是网络抓包。网络抓包是通过监听网络...

    IP包捕获与解析

    总的来说,"IP包捕获与解析"项目涵盖了网络编程、C++编程以及图形用户界面设计等多个方面。通过这个项目,我们可以深入了解网络通信的底层机制,学习如何在实际应用中使用libpcap和MFC,这对于网络分析和网络安全等...

    28181 ps流解析成es流,rtp包解析

    总的来说,从28181 PS流解析成ES流,再到RTP包解析,是一个复杂而关键的过程,涉及到了多媒体数据的传输、同步和处理等多个环节。理解并掌握这一流程对于从事流媒体系统开发、网络视频监控以及相关领域的专业人士来...

    json 数据解析包

    标题提到的“json 数据解析包”是一组Java库,它们可以帮助开发者在Java环境中解析和操作JSON数据。以下是这些库的详细介绍: 1. **commons-collections-3.2.jar**:Apache Commons Collections是Apache软件基金会...

    计算机网络ip包解析代码 试验代码

    这份代码提供了对IP数据包逐层解析的实例,不仅能够帮助理解TCP/IP协议栈的工作原理,而且对于学习如何使用套接字编程捕获和解析网络数据包具有重要意义。此外,它还可以作为网络监控、网络安全分析和网络性能测试的...

    Android 动态解析网络布局

    在Android开发中,动态解析网络布局是一项重要的技术,它允许开发者根据服务器返回的JSON数据动态构建用户界面,提高应用的灵活性和可扩展性。本文将深入探讨如何在Android中实现这一功能。 首先,理解JSON...

    头哥ICMP Ping实现-解析IP包ICMP头信息.txt

    头哥ICMP Ping实现-解析IP包ICMP头信息.txt头哥ICMP Ping实现-解析IP包ICMP头信息.txt头哥ICMP Ping实现-解析IP包ICMP头信息.txt头哥ICMP Ping实现-解析IP包ICMP头信息.txt头哥ICMP Ping实现-解析IP包ICMP头信息.txt...

    基于Libpcap实现的局域网嗅探抓包发包解析工具_嗅探抓包发包解析工具_

    基于Libpcap实现的局域;网嗅探抓包发包解析工具.

    包含html页面解析的网络爬虫程序C#实现

    在本项目"包含html页面解析的网络爬虫程序C#实现"中,开发者使用C#语言构建了一个能够解析HTML页面并将其转化为树形结构的爬虫。这个程序的核心功能包括HTML解析、内容提取以及数据存储。 1. **HTML页面解析**:...

    json解析包

    在编程中,理解并熟练使用JSON解析包是进行数据交换和网络通信的基础。无论你是Web开发者还是后端工程师,掌握JSON的解析和序列化技巧都是必备技能。通过学习和实践,你可以更高效地处理JSON数据,提升代码的可读性...

    java实现网络抓包

    Java 实现网络抓包主要涉及网络通信协议的理解、数据包捕获与解析、以及HTTP协议的深入认识。在这个过程中,开发者通常会用到Java的Socket编程、数据流处理以及第三方库,如Jpcap或Wireshark的Java绑定库。 首先,...

Global site tag (gtag.js) - Google Analytics