通信协议的解析:字节流协议的解析
2013-10-11 08:53
429 查看
由于字节流协议具有共同的特点,因此解析也就很简单,主要涉及两种设计模式:模板方法,命令模式。
解析的基本步骤:
1判断一个完整帧的开始,根据协议规定判断帧的开始字节
2获取一个完整的帧。主要有两种,一种是根据根据帧的开始字节结束字节判断一个完整的帧,一种是根据开始帧和帧长度判断
3得到一个完整的帧后,根据命令字创建不同的命令,根据不同的命令字分别处理。
通过模板方法解析帧,由于不同的命令具体组成不一样,所以根据命令字创建不同的命令,使用命令模式,具体处理每一个解析出来的帧。
以下为一个具体的解析例子,只需要简单修改,就可以在实际中使用
解析的基本步骤:
1判断一个完整帧的开始,根据协议规定判断帧的开始字节
2获取一个完整的帧。主要有两种,一种是根据根据帧的开始字节结束字节判断一个完整的帧,一种是根据开始帧和帧长度判断
3得到一个完整的帧后,根据命令字创建不同的命令,根据不同的命令字分别处理。
通过模板方法解析帧,由于不同的命令具体组成不一样,所以根据命令字创建不同的命令,使用命令模式,具体处理每一个解析出来的帧。
以下为一个具体的解析例子,只需要简单修改,就可以在实际中使用
public class DataProcess { protected List<byte> fragment = new List<byte>();//保存上次处理后,剩余的字节 /// <summary> /// 对外调用的方法 /// </summary> /// <param name="newReceivedData">新接收到的字节数据</param> public void ProcessData(byte[] newReceivedData) { try { fragment.AddRange(newReceivedData);//把新收到的数据和上次处理的数据合并 var data = new List<byte>(); data.AddRange(fragment); List<byte[]> 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("处理设备数据出错。"); } } /// <summary> /// 循环解析帧 /// </summary> /// <param name="data"></param> /// <returns></returns> protected List<byte[]> ParseFrames(List<byte> data) { List<byte[]> Frames = new List<byte[]>(); 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; } /// <summary> /// 需要根据实际情况重写 /// </summary> /// <param name="frame"></param> protected void ProcessFrame(byte[] frame) { int commandTypeIndex = 2;//第三个字节规定命令类型 int commandByte = frame[commandTypeIndex]; switch (commandByte) //根据命令的不同,生成的command分别处理,使用命令模式 { case 1: // break; case 2: break; case 3: break; } } /// <summary> /// 处理解析帧后,剩余的数据 /// </summary> /// <param name="frag"></param> protected void SaveFragment(List<byte> frag) { int maxFragmentLength = 1000; //未处理的帧的最大长度 //遗留数据片段过长,有问题。未防止内存压力过大,需要清空fragment if (frag.Count > maxFragmentLength) { frag = new List<byte>(); } fragment.Clear(); fragment.AddRange(frag); if (frag.Count > 0) { log(string.Format("剩余数据片段:{0}", frag)); } } /// <summary> /// 需要根据实际情况重写 /// </summary> /// <param name="data"></param> /// <returns></returns> private static int GetFrameStartIndex(List<byte> 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;//默认值,没有找到帧头 } /// <summary> /// 需要根据实际情况重写 /// </summary> /// <param name="datas"></param> /// <returns></returns> private static int GetFrameEndIndex(List<byte> 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;//帧不完整 } /// <summary> /// 获取一个完整的帧的所有字节 /// </summary> /// <param name="data"></param> /// <param name="frameStartIndex">帧的开始位置</param> /// <param name="frameEndIndex">帧的结束位置</param> /// <returns></returns> private static byte[] GetOneFrame(List<byte> 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) { } }
相关文章推荐
- 通信协议的解析:字节流协议的解析
- Arduino自定义通信协议解析
- HDFS各个节点间的通信协议-RPC解析
- 网络通信—协议详细解析 大致结构
- Android 蓝牙通信及自定义消息协议的解析和生成
- ANDROID ACCESSORY 通信协议建立过程 -----解析好后可以在单片机做主机来于安卓手机通信
- iOS远程真机之iTunes与iPhone的通信协议usbmuxd解析
- [置顶] 通信协议中多字节数据的解析
- adb 通信协议分析以及实现 (三) (Adb 网络通信部分解析)
- Android 蓝牙通信及自定义消息协议的解析和生成
- 【C#串口编程计划】通信协议解析 -- byte[]与常用类型的转换
- Ubuntu下GCC之libpcap库数据库通信协议解析基础框架代码
- MAVLink协议通信分析——(三)消息解析
- Android java层与C层通过localsocket通信、通信协议制定与解析。
- 字符串通信协议解析函数
- Android java层与C层通过localsocket通信、通信协议制定与解析。
- 通信协议之点阵的解析和showWindow问题的解决
- TCPIP-TCP是一种面向连接(连接导向)的、可靠的、基于字节流的运输层(Transport layer)通信协议
- Ituns与iphone的通信协议usbmuxd解析
- Ituns与iphone的通信协议usbmuxd解析