Chinaunix首页 | 论坛 | 博客
  • 博客访问: 186140
  • 博文数量: 89
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 828
  • 用 户 组: 普通用户
  • 注册时间: 2013-10-08 10:44
文章分类
文章存档

2014年(9)

2013年(80)

我的朋友

分类: C#/.net

2013-10-11 20:15:31

    由于字节流协议具有共同的特点,因此解析也就很简单,主要涉及两种设计模式:模板方法,命令模式。
   解析的基本步骤:
    1判断一个完整帧的开始,根据协议规定判断帧的开始字节
    2获取一个完整的帧。主要有两种,一种是根据根据帧的开始字节结束字节判断一个完整的帧,一种是根据开始帧和帧长度判断
    3得到一个完整的帧后,根据命令字创建不同的命令,根据不同的命令字分别处理。
    通过模板方法解析帧,由于不同的命令具体组成不一样,所以根据命令字创建不同的命令,使用命令模式,具体处理每一个解析出来的帧。
  以下为一个具体的解析例子,只需要简单修改,就可以在实际中使用
[csharp] view plaincopy
public class DataProcess  
{  
    protected List fragment = new List();//保存上次处理后,剩余的字节  
  
  
    ///  
    /// 对外调用的方法  
    ///
 

    /// 新接收到的字节数据  
    public void ProcessData(byte[] newReceivedData)  
    {  
        try  
        {  
            fragment.AddRange(newReceivedData);//把新收到的数据和上次处理的数据合并  
            var data = new List();  
            data.AddRange(fragment);  
            List frames = ParseFrames(data);//解析帧  
            if (frames.Count > 0)  
            {  
                try  
                {  
                    for (int i = 0; i < frames.Count; i++)  
                    {  
                        log(string.Format("处理数据:{0}", frames[i]));  
                        ProcessFrame(frames[i]);//处理帧  
                    }  
  
  
                }  
                catch (Exception ex)  
                {  
  
  
                    throw ex;  
                }  
            }  
            SaveFragment(data);//保存此次处理后剩余的片段  
        }  
        catch (Exception ex)  
        {  
            log("处理设备数据出错。");  
        }  
    }  
  
  
    ///  
    /// 循环解析帧  
    ///
 

    ///  
    ///  
    protected List ParseFrames(List data)  
    {  
        List Frames = new List();  
        int frameStartIndex = GetFrameStartIndex(data);//判断帧的开始  
        while (frameStartIndex >= 0)  
        {  
            int frameEndIndex = GetFrameEndIndex(data, frameStartIndex);//判断帧的结束  
            if (frameEndIndex < 0)//帧不完整  
            {  
                return Frames;  
            }  
            byte[] OneFramebyte = GetOneFrame(data, frameStartIndex, frameEndIndex);  
            Frames.Add(OneFramebyte);  
            //data.RemoveRange(0, frameStartIndex);//可以有这一句,避免不完整的帧,对后续解析造成影响  
            data.RemoveRange(frameStartIndex, frameEndIndex - frameStartIndex);//移除已经处理的数据  
            frameStartIndex = GetFrameStartIndex(data);  
        }  
        return Frames;  
    }  
  
  
    ///  
    /// 需要根据实际情况重写  
    ///
 

    ///  
    protected void ProcessFrame(byte[] frame)  
    {  
        int commandTypeIndex = 2;//第三个字节规定命令类型  
        int commandByte = frame[commandTypeIndex];  
        switch (commandByte) //根据命令的不同,生成的command分别处理,使用命令模式  
        {  
            case 1:  
                //  
                break;  
            case 2:  
                break;  
            case 3:  
                break;  
        }  
  
  
    }  
  
  
    ///  
    /// 处理解析帧后,剩余的数据  
    ///
 

    ///  
    protected void SaveFragment(List frag)  
    {  
        int maxFragmentLength = 1000; //未处理的帧的最大长度  
        //遗留数据片段过长,有问题。未防止内存压力过大,需要清空fragment  
        if (frag.Count > maxFragmentLength)  
        {  
            frag = new List();  
        }  
        fragment.Clear();  
        fragment.AddRange(frag);  
        if (frag.Count > 0)  
        {  
            log(string.Format("剩余数据片段:{0}", frag));  
        }  
  
  
    }  
  
  
    ///  
    /// 需要根据实际情况重写  
    ///
 

    ///  
    ///  
    private static int GetFrameStartIndex(List data)  
    {  
        byte FrameStartByte1 = 0x08;  
        byte FrameStartByte2 = 0x04;  
        //x8,0x04   
        for (int i = 0; i < data.Count - 1; i++)  
        {  
            if (data[i] == FrameStartByte1 && data[i + 1] == FrameStartByte2) //帧头是0x08,0x04两个字节开始  
            {  
                return i;  
            }  
        }  
        return -1;//默认值,没有找到帧头  
    }  
  
  
    ///  
    /// 需要根据实际情况重写  
    ///
 

    ///  
    ///  
    private static int GetFrameEndIndex(List data, int frameStartIndex)  
    {  
        int FrameStartBytesLegnth = 2;//帧头的字节个数  
        if (frameStartIndex + FrameStartBytesLegnth < data.Count - 1)  
        {  
            int length = data[frameStartIndex + 2];//第四个字节规定整个帧的长度  
            if (length + frameStartIndex < data.Count)  
            {  
                return length + frameStartIndex;  
            }  
            return -1;//虽然包含了帧头,但不完整  
        }  
        /*  规定了帧的结束字符的情况 
       for (int i = frameStartIndex + 1; i < data.Count - 1; i++) 
       { 
           if (data[i] == 0x08 && data[i + 1] == 0x03) //帧头是0x08,0x03两个字节结束一个完整的帧 
           { 
               return i + 1; 
           } 
       } */  
        return -1;//帧不完整  
    }  
    ///  
    /// 获取一个完整的帧的所有字节  
    ///
 

    ///  
    /// 帧的开始位置  
    /// 帧的结束位置  
    ///  
    private static byte[] GetOneFrame(List data, int frameStartIndex, int frameEndIndex)  
    {  
        var OneFramebyte = new byte[frameEndIndex - frameStartIndex];  
        Array.Copy(data.ToArray(), frameStartIndex, OneFramebyte, 0, frameEndIndex - frameStartIndex);  
        return OneFramebyte;  
    }  
  
  
  
  
    private static void log(string info)  
    {  
  
  
    }  
  
  
}  
阅读(2803) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~