一般是这样的:
dim rData as string
private sub mysock_DataArrival(byval totalbytes as long)
dim s as string
mysock.GetData s
rData = rData & s
'处理数据
'判断是否已经接收大了一个完整的数据包。
'假设已经收到了一个数据包,它的长度是n,
dim pack as string
pack = Left$(rData,n)
ProcessPackage pack
rData = Mid$(rData,n+1)
end sub所有使用TCP的数据流,都有自己的数据包的开始和结束的定义的规范,常见的有两种方式:
1:数据包的开始4个或2个字节就是这个包的长度
2:数据包是以某个特殊标志结束的。比如:CRLF CRLF(两个换行),
HTTP协议:
协议头数据包(HTTP HEADER)就是以两个换行作为结束标志,接下来的内容数据(content)的长度就由(HTTP HEADER)中的Content-Length指定的。(也可能有其他方式)由于VB按字节处理不太方便,所以如果是你自己定义传输格式的话,最好统一使用字符串。还有一点要注意:TCP流只保证发送和接收的正确顺序,并不保证发送的数据块大小和接收的相同。比如:分两次发送1000+4000个字节,就可能分三次收到2000+2000+1000,也可能一次就收到5000个字节
dim rData as string
private sub mysock_DataArrival(byval totalbytes as long)
dim s as string
mysock.GetData s
rData = rData & s
'处理数据
'判断是否已经接收大了一个完整的数据包。
'假设已经收到了一个数据包,它的长度是n,
dim pack as string
pack = Left$(rData,n)
ProcessPackage pack
rData = Mid$(rData,n+1)
end sub所有使用TCP的数据流,都有自己的数据包的开始和结束的定义的规范,常见的有两种方式:
1:数据包的开始4个或2个字节就是这个包的长度
2:数据包是以某个特殊标志结束的。比如:CRLF CRLF(两个换行),
HTTP协议:
协议头数据包(HTTP HEADER)就是以两个换行作为结束标志,接下来的内容数据(content)的长度就由(HTTP HEADER)中的Content-Length指定的。(也可能有其他方式)由于VB按字节处理不太方便,所以如果是你自己定义传输格式的话,最好统一使用字符串。还有一点要注意:TCP流只保证发送和接收的正确顺序,并不保证发送的数据块大小和接收的相同。比如:分两次发送1000+4000个字节,就可能分三次收到2000+2000+1000,也可能一次就收到5000个字节
解决方案 »
- VB 如何实现 畸形 界面(不规则窗体)???
- dblist如何关联?
- 关于vb+access检索日期的sql语句
- set picture1.picture=picture1.image语句,为什么偶尔失效?
- VB如何實現無符號Long型值計算?
- 向高手求援呀!!! (不好意思,只剩下10分了)
- 唉,太累了,想请一两个帮手(VB), 1500元/每月,不知有没有人感兴趣?
- 请问如何通过Range("A1").Column这样的方法获得某个Cell的行数?
- 已知一图片地址如果用程序下载包括显示进度条谢谢?
- EXCEL数据库
- vb用excel问题
- 请问谁知道详细windows的休眠功能原理,是不是调用中断?
我在MSDN上看到分批得到数据时不激发dataarrival事件,随时检测sck.BytesReceived,如果大于零就GetData把缓冲清掉。
现在的问题是,当检测到最有一批数据时,服务器已经关闭连接,sck.GetData出错。
那位高手知道?
多谢回答。
问题的核心就是:我知道我已经接收的数据还没有结束(即小于服务器发送的数据) ,我如何再一次接收??多谢!
分享一下:
处理DataArrival事件
private Sub sckClient_DataArrival(ByVal bytesTotal As Long)
Dim szBuffer As String
sckClient.GetData szBuffer
OutputText szBuffer + vbCrLf
ReceiveData 'loop function
OutputText "Transfer compeleted!"+vbcrlf
sckClient.Close
End SubPrivate sub ReceiveData()
Const nTimeOut = 30
Dim nStartTime As Single
Dim szBuffer As String
nStartTime = Timer
sckClient.GetData szBuffer
OutputText szBuffer
Do While sckClient.BytesReceived = 0
DoEvents
If Int(Timer - nStartTime) >= nTimeOut Then Exit Do
If sckClient.BytesReceived <> 0 Then
If sckClient.State <> 7 Then Exit Do
sckClient.GetData szBuffer
SetText szBuffer
End If
Loop
End sub
接收的数据并不是以发送的数据包为单位的。所以在确认接收到完整的数据之前,必须准备一个buffer把收到的数据连接起来,这是tcp编程的基本原则,更不能在中间加上VbCrLf之类的东西。每次有新的数据到来,都会有DataArrival事件产生,你上面引用的某个MSDN的说明一定是你的误解。如果你只是简单的显示来自HTTP SERVER的数据,这个程序只是用来玩一玩,你可以这样做,否则,即使数据接收问题解决了,还有许多其他问题,比如
1:怎样通过代理服务器
2:返回的数据是经过编码的。例如Transfer-Encoding: chunked
3:返回的数据需要重定向。
等等。
建议你可以使用Web控件,或使用WinetAPI
DataArrival Event:
This event will not occur if you do not retrieve all the data in one GetData call. It is activated only when there is new data. Use the BytesReceived property to check how much data is available at any time.以上的程序很不好,但是基本思想如此。我并没有把得到的数据分开,更没有加上vbcrlf之类的东西,我的OutputText是一个子程序用来向RichTextBox输出,其实richtextbox.text就相当于你所说的buffer.所谓的vbcrlf是用来输出我自己的信息的。这个程序是基于TCP/IP的,跟通不通过代理服务器有何关系?我在局域网内,照样可以得到http://www.990.net的数据。我只是简单的得到数据(文本),就算有编码问题,也应该先把数据存到本地才能解码。这个程序是用来得到远程主机的ASP源代码,只能用Winsock,不能用Web控件。多谢Taolei大虾的热心回答,希望问题继续讨论,我会给你加分的。呵呵
这是我改的:其实是把ReceiveData子程序拿进来而已。
Private Sub sckClient_DataArrival(ByVal bytesTotal As Long)
Dim szBuffer As String
sckClient.GetData szBuffer
SetText szBuffer + vbCrLf
Do While sckClient.BytesReceived = 0
If sckClient.State <> 7 Then Exit Do
DoEvents
Loop
nPackage = nPackage + 1
StatusBar1.Panels(1).Text = nPackage & " package received."
End Sub
dim s as string
sckClient.GetData s
就已经把本次数据全部接收了,所以不需要其他的处理。在事件处理程序中应该尽量快的处理数据,并离开这个过程,让VB可以做其他的事情。虽然你用DoEvents也可以在等待的同时让VB做其他事情,但在这里并无此必要,并且DoEvents并非能解决所有事情。另外,用String类型的变量来接收HTTP数据,除了上面我提到的问题外,还有:
1:如果Http Response的Content-Type是IMAGE或是其他的非文本类型,String变量不能正确接收。
2:如果内容里包含了双字节的汉字,有可能这个汉字的第一个字节是上一次接收的最后一个字节,而第二个字节是下一次接收的第一个字节,由于在VB中是分别转换的,所以会出现乱码。不要觉得这种情况发生的可能性很小,对于一个中文网页,这种情况会经常发生。你在这里并没有必要去分析HTTP数据的各种格式,否则就有不着Inet空件和WinetAPI了,分析他并不是一个简单的事。更正一下,让面提到的Web控件应该是Inet控件,全称是Microsoft Internet Transfer Control,它和WinSock控件同样都是Invisible at runtime。能用WinSock控件,当然也可以用这个控件,而且用法很简单。
再次多谢TaiLei兄指点。