一般是这样的:
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个字节

解决方案 »

  1.   

    不是啦,我是用TCP/IP模拟IE得到WEB上的数据,没看到端口是80吗?
    我在MSDN上看到分批得到数据时不激发dataarrival事件,随时检测sck.BytesReceived,如果大于零就GetData把缓冲清掉。
    现在的问题是,当检测到最有一批数据时,服务器已经关闭连接,sck.GetData出错。
    那位高手知道?
      

  2.   

    To Taolei:
      多谢回答。
      问题的核心就是:我知道我已经接收的数据还没有结束(即小于服务器发送的数据) ,我如何再一次接收??多谢!
      

  3.   

    哈哈,还是我自己搞定了!!!
    分享一下:
     处理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
      

  4.   

    socket控件是异步socket,VB是单线程的,所以编程的思想一定要以消息触发为主。题外话。
    接收的数据并不是以发送的数据包为单位的。所以在确认接收到完整的数据之前,必须准备一个buffer把收到的数据连接起来,这是tcp编程的基本原则,更不能在中间加上VbCrLf之类的东西。每次有新的数据到来,都会有DataArrival事件产生,你上面引用的某个MSDN的说明一定是你的误解。如果你只是简单的显示来自HTTP SERVER的数据,这个程序只是用来玩一玩,你可以这样做,否则,即使数据接收问题解决了,还有许多其他问题,比如
    1:怎样通过代理服务器
    2:返回的数据是经过编码的。例如Transfer-Encoding: chunked
    3:返回的数据需要重定向。
    等等。
    建议你可以使用Web控件,或使用WinetAPI
      

  5.   

    这是MSDN的原文:
    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大虾的热心回答,希望问题继续讨论,我会给你加分的。呵呵
      

  6.   

    另外,不知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
      

  7.   

    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.应该这样理解:新的数据来的时候会产生事件,在事件处理程序里你应该把这次到来的数据全部接收。事实上
    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控件,当然也可以用这个控件,而且用法很简单。
      

  8.   

    哈哈,对不起,是我搞错了,我以为接收不到全部数据,原来是因为我在DataArrival的最后加了一个sckClient.Close,真是糊涂啊!
    再次多谢TaiLei兄指点。