| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 976 人关注过本帖
标题:[分享]一个用于处理“简单的自定义通信协议被拆分”的缓存类
取消只看楼主 加入收藏
jiashie
Rank: 8Rank: 8
等 级:贵宾
威 望:10
帖 子:237
专家分:999
注 册:2009-4-30
结帖率:100%
收藏
已结贴  问题点数:20 回复次数:1 
[分享]一个用于处理“简单的自定义通信协议被拆分”的缓存类
定义一套较简单的自定义通信协议,用于在串口或者winsock通信中。
比如,发送方:“@12L05@ + 固定长度的数据 ”表示 某个意思
接收方检测到(从串口或winsock)接收的字符串中包含了特定的命令标志“@12L05@”,就把之后的固定长度的数据保存下来(或者其它处理)。
正常情况下,如果“@12L05@ + 固定长度的数据 ”一次性接收完成,在接收方检测命令和提取数据是不会出问题的。但是,当一个完整的“数据包”被拆分到达之后,在接收方就有可能检测不到或者取数据不正常。
比如:“@12L05@ + 固定长度的数据 ”被拆分成“上一次未发送完的n个字节的数据 + @12” ,到达接收方后,检测不到“@12L05@”,于是认为是无关的数据,丢弃,下次接收到剩下的“L05@ + m长度的数据 ”,仍然检测不到“@12L05@”,再次丢弃。如此循环,有可能永远都收不到数据了。
为了解决这种类型的问题,先把接收到的数据放到缓存,再检测当前的缓存中是否包含指定的命令,且命令后的数据长度符合要求。如果符合,则提取出一个完整的“数据包”,并从缓存中清除。从而防止了数据包被拆分到达接收端后无法识别的问题。
代码如下:
程序代码:
Option Explicit

Private m_Cache As String
Private m_Count As Long

Private Type CMD_TYPE
    cmd_Start As String
    cmd_Len As Long
End Type
Private m_Cmd() As CMD_TYPE
'Private m_Cmd As Dictionary
Private cmdCount As Long
Private Const ERROR_USER As Long = 531

Public Function SetData(ByVal strValue As String) As Long
    m_Cache = m_Cache & strValue
    m_Count = m_Count + Len(strValue)
End Function

Public Function GetData(Optional ByVal bGetAll As Boolean = False) As String
On Error GoTo errHandler

Dim i As Long
Dim j As Long
Dim nPos As Long
Dim nIndex As Long
Dim strRet As String

If bGetAll Then
    GetData = m_Cache
    Exit Function
End If

'从头开始查找第一个符合命令的位置,避免由于cmd的添加顺序不同,先取出后面的数据,而丢弃前面的数据
nPos = m_Count
For i = 0 To cmdCount - 1
    j = InStr(1, m_Cache, m_Cmd(i).cmd_Start)
    If j = 1 Then
        nPos = j
        nIndex = i
        Exit For
    Else
        If j < nPos And j > 0 Then
            nPos = j
            nIndex = i
        End If
    End If
Next

If nPos > 0 And nPos < m_Count And nPos + m_Cmd(nIndex).cmd_Len - 1 <= m_Count Then
    strRet = Mid$(m_Cache, nPos, m_Cmd(nIndex).cmd_Len)
    m_Cache = Mid$(m_Cache, nPos + m_Cmd(nIndex).cmd_Len)
    m_Count = m_Count - nPos - m_Cmd(nIndex).cmd_Len + 1
End If

GetData = strRet
Exit Function
errHandler:
    Debug.Print Err.Number, Err.Description
    #If debug_mode Then
        Stop: Resume
    #End If
    GetData = ""
End Function

Public Function ClearData() As Long
    m_Cache = ""
    m_Count = 0
End Function

Public Function AddCmd(ByVal cmdStart As String, ByVal cmdLen As Long) As Long
On Error GoTo errHandler

'TODO:检查是否已有重复的cmd

If cmdStart = "" Or cmdLen < Len(cmdStart) Then
    Err.Raise ERROR_USER, , "命令格式错误"
End If

cmdCount = cmdCount + 1
ReDim Preserve m_Cmd(cmdCount - 1) As CMD_TYPE
m_Cmd(cmdCount - 1).cmd_Start = cmdStart
m_Cmd(cmdCount - 1).cmd_Len = cmdLen

AddCmd = 0
Exit Function
errHandler:
    Debug.Print Err.Number, Err.Description
    #If debug_mode Then
        Stop: Resume
    #End If
    AddCmd = -1
End Function

Private Sub Class_Initialize()
m_Cache = ""
m_Count = 0

cmdCount = 0
ReDim m_Cmd(cmdCount) As CMD_TYPE
End Sub

Private Sub Class_Terminate()
    Erase m_Cmd
    m_Cache = ""
End Sub


测试代码如下:
程序代码:
Private Sub Command1_Click()
Dim a As Cache
Set a = New Cache

a.SetData "@12L05@helloworld"
a.SetData "1234567890"
Debug.Print a.GetData, a.GetData(True)
a.AddCmd "@12L05@", 27
Debug.Print a.GetData
a.SetData "@12L05@helloworld"
Debug.Print a.GetData, a.GetData(True)
a.ClearData

Debug.Print "拆分的命令"
a.SetData "abcdefg@12L"
Debug.Print a.GetData, a.GetData(True)
a.SetData "05@1234567890"
Debug.Print "数据长度不足"
Debug.Print a.GetData, a.GetData(True)
a.SetData "1234567890abcdef"
Debug.Print "长度已足够,能够识别"
Debug.Print a.GetData, a.GetData(True)

a.AddCmd "fml", 10
a.SetData "mlzhangwj@12L05@helloworld1234567890"
Debug.Print a.GetData, a.GetData(True)
Set a = Nothing
End Sub
搜索更多相关主题的帖子: 缓存 通信协议 定义 拆分 分享 
2010-07-14 11:24
jiashie
Rank: 8Rank: 8
等 级:贵宾
威 望:10
帖 子:237
专家分:999
注 册:2009-4-30
收藏
得分:0 
回复 2楼 风吹过b
起初我也是直接把接收的数据保存在某个变量里的,但是后来下位机又增加了一些命令,而且和以前的命令格式还有差别,就给整混乱了。
看来罪魁祸首还是没有事先定义好可扩展的协议的格式,需求又老是变动。
2010-07-14 15:09
快速回复:[分享]一个用于处理“简单的自定义通信协议被拆分”的缓存类
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.019745 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved