| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 6751 人关注过本帖
标题:VB winsock接收数据处理的问题
只看楼主 加入收藏
lianyicq
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:26
帖 子:737
专家分:3488
注 册:2013-1-26
收藏
得分:0 
回复 20楼 hcyang1422
我从17楼截的代码,遗漏了.
不能调试是容易出问题
          ReDim FileByte(UBound(temp) - 14)
          CopyMemory FileByte(0), temp(12), UBound(temp) - 13
这两句中的"temp"换为"str"

loc(1)是返回找开的1#文件当前的读写位置.
每一包到后数据都getdata到了str中,下一包到前都可以使用.
tmp=StrConv(1, vbUnicode)中的"1"是?


大开眼界
2015-05-04 16:57
hcyang1422
Rank: 1
等 级:新手上路
帖 子:20
专家分:0
注 册:2015-4-23
收藏
得分:0 
回复 21楼 lianyicq
我将代码作如下变更后
temp=str()
ReDim FileByte(UBound(temp) - 1)
          CopyMemory FileByte(0), temp(11), UBound(temp) - 1
未再出现错误提示,
但是If Loc(1) = strlen Then这句运行结果一直为false
我查看临时文件temp.bat,里面只有8k的数据,后面的数据未接收到。

现在这部分的接收和处理代码如下
请再帮忙看下8K之后数据未收到的原因,以及后面信息处理时全部数据转换字符串的过程是否正确。

  Case "EB"                                         '二进制数据返回,
       If ReceiveState = False Then
             Open "c:\temp.dat" For Binary As #1
             ReceiveState = True
             id = str(9)
          End If
          strlen = HEX_to_DEC(Hex(str(4)) & Hex(str(5)) & Hex(str(6)) & Hex(str(7))) + 8 '取数据长度,测试OK
          temp = str()
          ReDim FileByte(UBound(temp) - 14)
          copymemory FileByte(0), temp(12), UBound(temp) - 13
          Put #1, , FileByte
          If Loc(1) = strlen Then
             ReceiveState = False
             Select Case id
               Case id = 19                                                            'id为19时,取通道标记
               tmp = Mid(StrConv(1, vbUnicode), 6000, 10000)                           '将全部数据转换为字符串
               S3 = Split(tmp, "ST", , vbBinaryCompare)   '字符串分解,区分大小写
                'Text4.Text = Trim(s3)
                For i = 1 To UBound(S3)
                    s1 = Split(Split(S3(i), vbCrLf)(0), ",")(1)
                    s1 = Trim(s1)
                    Text2 = Text2 + s1 + vbCrLf
                    Form4.CHNAME(j - 1) = Trim(s1)
                Next i
                Case id=13
              End Select

'命令发送完成后,添加有如下状态设置,未全部接收数据是否与此有关?
Private Sub Winsock1_SendComplete()
If sdata = "FE4" Or sdata = "FC GET" Then
ReceiveState = 1
Else
ReceiveState = 0

End If
End Sub

[ 本帖最后由 hcyang1422 于 2015-5-4 17:26 编辑 ]
2015-05-04 17:19
lianyicq
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:26
帖 子:737
专家分:3488
注 册:2013-1-26
收藏
得分:0 
回复 22楼 hcyang1422
有两个问题没清楚:
1、每个包的第5~8字节是本包的数据长度,不是本次查询回传数据的总数;
2、验证第5~8字节,是否是高位在前,低位在后。一般是低位在前,高位在后。
如果第一个EB包不是本次查询回传二进制数据的总长度,以前代码就不对。只能靠检测是否是连续的EB包,即每次查询,设备第一个返回包总是EB包,若第N个包不是EB包,就说明本次查询的返回数据传送完成。

大开眼界
2015-05-05 08:45
hcyang1422
Rank: 1
等 级:新手上路
帖 子:20
专家分:0
注 册:2015-4-23
收藏
得分:0 
回复 23楼 lianyicq
对于你提出的问题,回答如下:
1;只有在12byte头包中的5-8位是本次查询回传数据总长度,后面的包中只包含数据,除最后的包以EN&VBCRLF&2byte校验值结尾外,没有任何标志。
2;5-8位是低位在前,高位在后的,而且这个顺序也有命令可以设置的。

如果你电脑上面装有Wireshark这个软件的话,可以下载一下18楼的附件,里面有整个数据返回时的抓包数据。
为了方便分析问题,我将抓包的数据转换成了TXT文档,并在相关内容后面加了注释。请参考附件。
HEX DATA.rar (20.09 KB)


[ 本帖最后由 hcyang1422 于 2015-5-5 10:25 编辑 ]
2015-05-05 09:55
lianyicq
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:26
帖 子:737
专家分:3488
注 册:2013-1-26
收藏
得分:0 
看了文本文件,是单包能完成的数据回传。
如果单包不能完成,是不是这样?
图片附件: 游客没有浏览图片的权限,请 登录注册

大开眼界
2015-05-05 10:39
hcyang1422
Rank: 1
等 级:新手上路
帖 子:20
专家分:0
注 册:2015-4-23
收藏
得分:0 
回复 25楼 lianyicq
不是单包可以发送完的,
你写的非单包数据格式基本正确,
不对的地方有以下3点
1:头包只有12byte,不包含数据
2:倒数第二包是以EN&VBCRLF结尾
3:最终的尾包只有2byte,即数据校验和
2015-05-05 10:58
lianyicq
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:26
帖 子:737
专家分:3488
注 册:2013-1-26
收藏
得分:0 
回复 26楼 hcyang1422
既然数据有结尾标志,就用结尾标志来决定后续事件。
试试
程序代码:
Dim ReceiveState As Boolean

Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
Dim S, S3, s1, flag, flag1 As String
Dim id, strlen As Integer
Dim tmp As String
Dim str() As Byte
Dim FileByte() As Byte

Winsock1.GetData str()

Select Case ReceiveState
  Case Is = True
    If str(UBound(str)) = &HD And str(UBound(str) - 1) = &HA And str(UBound(str) - 3) = Asc("E") And str(UBound(str) - 2) = Asc("N") Then
         ReDim FileByte(UBound(str) - 4)
         copymemory FileByte(0), str(0), UBound(str) - 3
         Put #1, , FileByte
         rectivestate = False
         Select Case id
           Case Is = 19
             '显示信息
         End Select
         Close #1
       Else
         Put #1, , str
    End If


 Case Is = False
   flag = Chr(str(8)) & Chr(str(9))
     Select Case flag

 
       '...
       Case "EB"     '二进制数据返回,
          If ReceiveState = False Then
             Open "c:\temp.dat" For Binary As #1
             ReceiveState = True
             id = str(9)
             'strlen = HEX_to_DEC(Hex(str(4)) & Hex(str(5)) & Hex(str(6)) & Hex(str(7)))
             Exit Sub
          End If
         
End Select

 
收到的鲜花
  • hcyang14222015-05-06 16:46 送鲜花  3朵   附言:我很赞同

大开眼界
2015-05-05 11:44
hcyang1422
Rank: 1
等 级:新手上路
帖 子:20
专家分:0
注 册:2015-4-23
收藏
得分:0 
回复 27楼 lianyicq
已按给出的方案修正了代码并测试了,有以下问题
1:当程序初始化过程中发送查询命令时,只能接收到19K的数据,前面的8K丢失了。
2:程序运行过程中再次发送查询命令时,数据可以全部接收,但是会累计在之前的数据后面。
   即重新接收数据时,在新建临时文件前的Kill "c:\temp.dat"命令没有运行。
3:Select Case id 没有运行,而且id的值也随着新数据包在变化,不能固定取值为头包中的值。
现贴出全部接收代码,请再帮忙看看
Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
Dim S, S3, s1, flag, flag1 As String
Dim id, strlen As Integer
Dim tmp As String
Dim str() As Byte
Dim temp() As Byte
Dim FileByte() As Byte

ReDim str(bytesTotal - 1)                                                                  '初始化接收缓冲区

Winsock1.getData str, vbByte + vbArray
Select Case ReceiveState
  Case Is = True
    If str(UBound(str)) = &HA And str(UBound(str) - 1) = &HD And str(UBound(str) - 3) = Asc("E") And str(UBound(str) - 2) = Asc("N") Then
         ReDim FileByte(UBound(str) - 4)
         CopyMemory FileByte(0), str(0), UBound(str) - 3
         Put #1, , FileByte
         ReceiveState = False
         Select Case id
           Case Is = 19                                                   '当id为19时,表示接收的为设定信息
             '显示信息
             tmp = Mid(StrConv(1, vbUnicode), 6000, 10000)                '将全部查询数据转换为字符串,并截取中间部分
               S3 = Split(tmp, "ST", , vbBinaryCompare)                   '字符串分解,区分大小写
                'Text4.Text = Trim(s3)
                For i = 1 To UBound(S3)
                    s1 = Split(Split(S3(i), vbCrLf)(0), ",")(1)           '取通道标记
                    s1 = Trim(s1)
                    Text2 = Text2 + s1 + vbCrLf
                    Form4.CHNAME(j - 1) = Trim(s1)                        
                Next i
         End Select
         Close #1
       Else
         Put #1, , str
    End If
    Case Is = False
    flag = Chr(str(0)) & Chr(str(1))
   
        Select Case flag
           
           Case "E1"                                        '登录
              Sleep 200
              Login   '登录
              log.Text = log.Text & Format(Hour(Time), "00") & ":" & Format(Minute(Time), "00") & ":" & Format(Second(Time), "00") & " " & "admin" & vbCrLf  '显示日志
        
          Case "E0"
               u = u + 1
               log.Text = log.Text & Format(Hour(Time), "00") & ":" & Format(Minute(Time), "00") & ":" & Format(Second(Time), "00") & " " & strdata   '显示日志
               log.SelStart = Len(log.Text)
                If u = 1 Then
            '     Sleep 500
                log.Text = log.Text & Format(Hour(Time), "00") & ":" & Format(Minute(Time), "00") & ":" & Format(Second(Time), "00") & " " & "登录成功" & vbCrLf   '显示日志
                state_lab = "TCP/IP Connect OK"                  '登录成功
                log.SelStart = Len(log.Text)
                End If
          Case "EA"                                         '温度值返回
               S = strdata
               log.Text = log.Text                          '不显示日志
               log.SelStart = Len(log.Text)
                S3 = Split(S, "^C", , vbTextCompare)
                For j = 1 To UBound(S3)
                    s1 = Split(S3(j), vbCrLf)(0)
                    s1 = Trim(s1)
                    If Format(s1) > Val(Form4.CH(j - 1)) Then
                    Form4.CH(j - 1) = Format(s1, "00.0")
                    End If
                Next j
           Case "EB"                                         '二进制数据返回,
               If ReceiveState = False Then
                     Kill "c:\temp.dat"
                     Sleep 100
                     Open "c:\temp.dat" For Binary As #1
                     ReceiveState = True
                     id = str(9)
                     Exit Sub
                  End If
          End Select
End Select
End Sub

[ 本帖最后由 hcyang1422 于 2015-5-5 18:59 编辑 ]
2015-05-05 18:55
lianyicq
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:26
帖 子:737
专家分:3488
注 册:2013-1-26
收藏
得分:0 
回复 28楼 hcyang1422
1:当程序初始化过程中发送查询命令时,只能接收到19K的数据,前面的8K丢失了。
2:程序运行过程中再次发送查询命令时,数据可以全部接收,但是会累计在之前的数据后面。
   即重新接收数据时,在新建临时文件前的Kill "c:\temp.dat"命令没有运行。
3:Select Case id 没有运行,而且id的值也随着新数据包在变化,不能固定取值为头包中的值。

1、2问题可能的解释就是第一个EB包除了12字节头以外,还包含数据。从你最早发的包格式图片看得出来。
临时文件建议在显示之后删除,也可以加代码另存。
第3问题的ID变化是否发生在一次查询返回的多个数据包时,难道一次查询会返回多个不同类型的数据文件?
写了这几次代码,分次接受的思路还是比较清晰了。

大开眼界
2015-05-06 09:18
hcyang1422
Rank: 1
等 级:新手上路
帖 子:20
专家分:0
注 册:2015-4-23
收藏
得分:0 
回复 29楼 lianyicq
现在我在代码判断包头Case "EB"部分加了写入数据后,现在已可以接收全部数据了,
但是数据接收完成后的Select Case id部分仍然没有运行。
为判断原因,我在取id后加入了debug语句查看了取值的结果,发现结果是正确的,
请再帮忙看看是什么原因造成的。
2015-05-06 10:40
快速回复:VB winsock接收数据处理的问题
数据加载中...
 
   



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

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