| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 6751 人关注过本帖
标题:VB winsock接收数据处理的问题
只看楼主 加入收藏
lianyicq
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:26
帖 子:737
专家分:3488
注 册:2013-1-26
收藏
得分:0 
回复 8楼 hcyang1422
我以前传大文件设缓冲区8192
客户端设一布尔变量receivedata,预设为false
receivedata为false时要分析包头.
首先由服务器端发"LEN"和 文件长度
客户端收到后,创建文件,置receivedata为True,发"PS"
服务端收到"PS",开始传文件
客户端收到数据后写文件,判断是否达到文件长度,如果没达到,发"CO"。如果达到了发"OV"并关闭文件,清零receivedata
服务器端收到"CO",则继续传,若收到"OV"则关闭文件。

现在你的情况是服务器端不能和客户端“握手”,由客户端自身判断是否是数据接收状态。但是如果有分包,总是数据连续发送吧。就直接由客户端接收到的字节数判断。
这和什么文件没什么关系吧,难道不同文件会混着传?把我上次说的第8字节开始取改为12字节开始.

大开眼界
2015-04-23 20:35
hcyang1422
Rank: 1
等 级:新手上路
帖 子:20
专家分:0
注 册:2015-4-23
收藏
得分:0 
回复 11楼 lianyicq
我再说明一下情况,我是通过winsock向仪器发出一条查询指令,然后仪器就开始通过异步方式返回数据,即仪器通过本身的协仪设定,开始不停的发送数据,直到数据发送完成。
返回的数据根据查询指令的不同,数据长度也不同,大部分数据一次GETDATA可以接收完成,但是当出现"EB"开头的数据时,返回数据的格式如之前提供的图片(12byte包头+DATA包+……+DATA包+校验和包),
不能一次GETDATA就接收完成,所以就只能考虑通过包头中的数据长度来进行特别处理,以完成接收全部数据,这也正是我搞不定,来求助的内容。
2015-04-23 22:36
renxiaoyao36
Rank: 9Rank: 9Rank: 9
来 自:七宝中学
等 级:贵宾
威 望:31
帖 子:347
专家分:1077
注 册:2014-9-18
收藏
得分:0 
你把头包设定一下特定语句,到时候GETDATA后先对得到的数据进行检查是否是头包,如果是,对之后接受到的数据进行检查,用Left函数检查开头的字符是否是标志,如果是,就将其和原来的存储组合包的变量合并,用&进行合并,千万不要用+号啊。

编程蛋疼的不是枯燥,而是辛辛苦苦编完几百行的代码,运行,“Runtime Error “xxx””。
2015-04-24 07:39
hcyang1422
Rank: 1
等 级:新手上路
帖 子:20
专家分:0
注 册:2015-4-23
收藏
得分:0 
回复 13楼 renxiaoyao36
我就是GETDATA后,先检查是否是头包标志,当出现较长的数据时,先取出数据长度的,后面的接收合并过程不太会处理。
请问,用下面红色代码进行接收后面的数据并合并,可以吗?不行的话请帮忙修改一下。
Case "EB"                                         '二进制数据返回,
      tmp = StrConv(str(), vbUnicode)
      id = str(9)                                   '取ID ,测试ok
      strlen = HEX_to_DEC(Hex(str(4)) & Hex(str(5)) & Hex(str(6)) & Hex(str(7)))            '取数据长度,测试OK
    if len(tmp)<strlen +8 then                '如果当前数据长度小于取得的当前数据量长度
     winsock1.getdata str()                    '再次取出数据
     tmp=tmp & strconv(str(),vbunicode)        '数据合并
     end if

         If id = 19 Then                               '如果ID为19,则为设定信息输出   
       此处为对接收的数据进行处理,同上面温度值取出
      End If
End Select
2015-04-24 08:36
风吹过b
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:364
帖 子:4947
专家分:30084
注 册:2008-10-15
收藏
得分:5 
如果后面的数据包也有 EB 标志,那么就使用你这种 select case  

12byte包头+DATA包+……+DATA包+校验和包
就是第二个 DATA包也是否包含 12字节的包头。


如果后面的数据包没有了 EB 了,那就必须使用状态来辅助。

if 状态=5  then
   取数据
判断是否结束
没有结束,连接起来,退出过程
  否则 状态=6 ,继续后面的包头分析
end if

分解包头
select case ...
case XX
状态=1
   ...

case "EB"
  状态=5                '设置状态,后面的数据直接连接,不分析包头的。  
  处理
case else
  状态=7               

end select  

-----------
随笔写的,希望你能看懂理解。

授人于鱼,不如授人于渔
早已停用QQ了
2015-04-24 08:50
lianyicq
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:26
帖 子:737
专家分:3488
注 册:2013-1-26
收藏
得分:0 
回复 12楼 hcyang1422
是在人家代码上作修改?在Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)中执行两次getdata?
仔细看看11楼的回复。
Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)事件发生后,执行getdata。
根据receivedata的值判断是接收数据还是分析包头。

[ 本帖最后由 lianyicq 于 2015-4-24 09:39 编辑 ]

大开眼界
2015-04-24 09:37
lianyicq
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:26
帖 子:737
专家分:3488
注 册:2013-1-26
收藏
得分:0 
有点时间,写了一个非应答方式的文件传送。以ReceiveStatus标志两种状态,以接收文件长度为结束标志。
程序代码:
Option Explicit
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Const SendBSize = 200
Dim ReceiveStatus As Boolean
Dim ReFiLen As Long

Private Sub Command1_Click()
Dim temp() As Byte
Dim i As Integer
Dim FileLenth As Long
Dim FileLenByte(3) As Byte
Dim FileLenLong(3) As Long


CommonDialog1.ShowOpen
Open CommonDialog1.FileName For Binary As #1
FileLenth = LOF(1)
FileLenLong(0) = FileLenth And &HFF& 'The data not belong to the long integer style must mark a & at the end.Important
FileLenLong(1) = (FileLenth And &HFF00&) / 256
FileLenLong(2) = (FileLenth And &HFF0000) / 65536
FileLenLong(3) = (FileLenth And &HFF000000) / 16777216

ReDim temp(2) As Byte
temp(0) = Asc("L")
temp(1) = Asc("E")
temp(2) = Asc("N")
SendSock.SendData temp

For i = 0 To 3
  FileLenByte(i) = FileLenLong(i)
Next

SendSock.SendData FileLenByte

ReDim temp(SendBSize) As Byte
While (Loc(1) < LOF(1))
  If (LOF(1) - Loc(1) < SendBSize) Then ReDim temp(LOF(1) - Loc(1) - 1)
  Get #1, , temp
  SendSock.SendData temp
Wend
Close #1
End Sub

Private Sub Form_Load()
ReceiveSOCK.Listen
SendSock.Connect
End Sub

Private Sub Form_Unload(Cancel As Integer)
ReceiveSOCK.Close
SendSock.Close
End Sub

Private Sub ReceiveSOCK_ConnectionRequest(ByVal requestID As Long)
If ReceiveSOCK.State <> sckClosed Then ReceiveSOCK.Close
ReceiveSOCK.Accept requestID
Form1.Caption = "Connect"

End Sub

Private Sub ReceiveSOCK_DataArrival(ByVal bytesTotal As Long)
Dim temp() As Byte
Dim FileByte() As Byte
Dim i As Integer
ReceiveSOCK.GetData temp, vbByte
Select Case ReceiveStatus
  Case Is = False
    ReceiveStatus = True
    ReFiLen = CLng(temp(3)) + CLng(temp(4)) * 256 + CLng(temp(5)) * 65536 + CLng(temp(6)) * 16777216 'temp(0-2)="LEN"
    ReceiveInfo.Text = ReceiveInfo.Text & ReFiLen & vbCrLf
    Open "c:\t.dat" For Binary As #2
    ReDim FileByte(UBound(temp) - 7)
    CopyMemory FileByte(0), temp(7), UBound(temp) - 6
    Put #2, , FileByte
  Case Is = True
    Put #2, , temp
End Select
If Loc(2) = ReFiLen Then
   ReceiveInfo.Text = ReceiveInfo.Text & "Send Complete." & vbCrLf
   ReceiveStatus = False
   Close #2
End If

End Sub


大开眼界
2015-04-28 15:15
hcyang1422
Rank: 1
等 级:新手上路
帖 子:20
专家分:0
注 册:2015-4-23
收藏
得分:0 
回复 17楼 lianyicq
非常感谢您能抽空写代码帮我解决问题,可惜本人太小白了,依然没有领悟出解决方法。
现在针对我的问题,我有以下方案,
我只有对仪器发出两组命令的时候才会出现数据量大于8192字节的情况
所以我在发出命令后设置一个状态符dataflag=true
接收端处理时,当状态符为dataflag=true时以byte型接收,否则以string型接收
但是在出现byte型数据时,我的代码仍然不能按预期接收数据,
经实测,数据长度每次会递增12字节,但是全部为0.请帮忙看看此处如何修改才能完整的接收数据。
为便于分析问题,再次添加数据格式以及仪器输出数据时使用Wireshark抓取的数据包
接收代码如下
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(), tmp() As Byte
Dim lngDataSize As Long

lngDataSize = 0                                                                            '初始化接收到的数据量
ReDim str(bytesTotal - 1)                                                                  '初始化接收缓冲区
'=======================================
'数据接收过程
'=======================================
If dataflag Then                                                                        '判断接收类型,为真时,接收类型为Byte
    '循环接收数据,直到接收数据长度等于应收数据长度
    Do
    Winsock1.getData str, vbByte + vbArray
    id = str(9)                                                                            '取ID ,测试ok
    strlen = HEX_to_DEC(Hex(str(4)) & Hex(str(5)) & Hex(str(6)) & Hex(str(7)))             '取数据长度,完整数据长度为此长度+8
    ReDim tmp(lngDataSize + bytesTotal - 1) As Byte
    copymemory tmp(), str(0), bytesTotal
    lngDataSize = lngDataSize + bytesTotal
    loop until  lngDataSize=stren+8               
                                       
   
    '数据接收完成后的预处理
    strdata = StrConv(str(), vbUnicode)                                                    '转换为字符串,
    flag = Left(strdata, 2)                                                                '取数据类型标志
   
    Else
    Winsock1.getData strdata                                                               '接收类型为string
    flag = Left(strdata, 2)
End If
'===================================
'     接收数据处理过程
'===================================
Select Case flag                                   '数据处理类型标志   
  Case "E1"                                        '登录     
  Case "E0"      
  Case "EA"                                         '温度值返回
  Case "EB"                                         '二进制数据返回,
data format&Wireshark data.rar (29.03 KB)


[ 本帖最后由 hcyang1422 于 2015-4-30 16:27 编辑 ]
2015-04-30 16:25
lianyicq
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:26
帖 子:737
专家分:3488
注 册:2013-1-26
收藏
得分:0 
回复 18楼 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()

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)
          End If
          strlen = HEX_to_DEC(Hex(str(4)) & Hex(str(5)) & Hex(str(6)) & Hex(str(7)))   '取数据长度,测试OK
          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 Is = 19
                 '显示信息
             End Select
                         
             Close #1
         
          End If
End Select
事实上ID号用来决定接收文件的类型(扩展名)。
在接收到EB的第一包时,就可以新建该类型文件。显示信息是在二进制文件传送完成之后,你也可以加一个开关来决定是否显示。
接收数据建议用二进制方式,避免转码,除非主要是传送文本。

大开眼界
2015-05-04 11:33
hcyang1422
Rank: 1
等 级:新手上路
帖 子:20
专家分:0
注 册:2015-4-23
收藏
得分:0 
回复 19楼 lianyicq
非常感谢抽空帮我解决问题
按照你给的方法我进行了测试,在下面这句代码处出现下标越界错误
ReDim FileByte(UBound(temp) - 14)
我将代码作如下变更后
ReDim FileByte(UBound(temp) - 1)
          CopyMemory FileByte(0), temp(11), UBound(temp) - 1
未再出现错误提示,
但是If Loc(1) = strlen Then这句运行结果一直为false
我查看临时文件temp.bat,里面只有8k的数据,后面的数据未接收到。

另外Loc(1) = strlen这句代码中的1代表的就是上面产生的临时数组#1吗?
在后面的处理中,如果我要把全部的数据转换为字符串,
是否可以用tmp=StrConv(1, vbUnicode)得到全部20多K数据?

[ 本帖最后由 hcyang1422 于 2015-5-4 17:00 编辑 ]
2015-05-04 16:34
快速回复:VB winsock接收数据处理的问题
数据加载中...
 
   



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

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