winsock为什么只能收到http头信息,无法接收到文件的本身呢?

winsock为什么只能收到http头信息,无法接收到文件的本身呢?

奇怪。受到下面数据后,如何继续接受图片呢?

现在只能接收到HTTP信息头,无法接受文件内容?而且bytesTotal 的长度是头信息的长度,而不是文件长度。请问如何继续接收数据内容呢/?

HTTP/1.0 200 OK
Content-Length: 6813
Content-Type: image/gif
Last-Modified: Mon, 04 Dec 2006 10:34:41 GMT
Accept-Ranges: bytes
ETag: "32cc86ce8f17c71:2bad"
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Date: Sun, 07 Jan 2007 09:23:53 GMT
Age: 100
X-Cache: HIT from longrujun.name
Via: 1.0 longrujun.name:80 (squid/2.6.STABLE5-20061211)
Connection: close

------------------------------------
接受代码:

Private Sub sk_DataArrival(Index As Integer, ByVal bytesTotal As Long) '收到数据触

    Dim str As String, i As Integer, j As Integer
    Dim url As String, tmp As String
    ReDim byBuff(1 To bytesTotal) As Byte
    sk(0).getData byBuff, vbArray + vbByte
    Open "img.gif" For Binary As #1
    Put #1, , byBuff
    Close #1
end sub

 

 

帅哥你只是连接了80端口,收到的是连接信息。
你需要看看http协议。要获得http报文,你需要发送post或者get请求

 多谢指点.

但是我的完整代码如下:

private sub command1_click()
        HTTPHeader = "GET /images/smilies/wizenflower.gif HTTP/1.1" & vbCrLf & _
                     "Content-Type: text/html" & vbCrLf & _
                     "Host: www.vbgood.com" & vbCrLf & _
                     "Accept: text/html, */*" & vbCrLf & _
                     "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Maxthon; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" & vbCrLf &  vbCrLf

         socks.Connect "www.vbgood.com", "80"
End Sub

Private Sub socks_Connect()
    socks.SendData HTTPHeader
End Sub

 

首先你要明白下载文件的过程机制。我这几天正在写WINSOCK,把我的经验告诉你吧。
1、发送HTTP头:
首先构建最简请求字符串:
dim HTTPHeader as string
HTTPHeader=""
HTTPHeader=HTTPHeader & "GET /images/smilies/wizenflower.gif HTTP/1.1" & vbCrLf
HTTPHeader=HTTPHeader & "Host: www.vbgood.com" & vbCrLf & vbCrLf
这样的头就可以了。

然后发送请求:
socks.Connect "www.vbgood.com", "80"

然后在connet事件时:
socks.SendData HTTPHeader

2、接收数据
这里是关键。服务器返回的数据有2部分组成。一部分是HTTP响应消息头,另一部分是你要下载的文件二进制数据。服务返回的数据不一定是几次,有可能一次,有可能二次,或者N次,而且响应消息头和返回的二进制数据不一定是分开的,有可能是一起返回,有可能第一次返回消息头,第二次返回二进制数据。服务器不同二不同。而且每次返回的数据大小最大是64KB,这是TCP包的最大尺寸。
你接收不到文件的问题就是出在你只接在ARRIVAL事件收一次数据,这当然是不全的。你应该首先在响应头中查找content_lenth,确定返回的数据总大小。然后定义一个全程byte()字节数组变量,分多次接收返回的数据,用ubound(byte)判断是否已经接收完全。大概思路就是这样,废话不多说,给你我的代码,我已经测试通过。

我写的是支持多线程(多winsock同时下载的代码),不懂的问。

调用方法:在data_Arrival()中
        Dim DataByte() As Byte  '用字节数组接受数据
        socks.GetData DataByte
        If SaveData(DataByte(), "wizenflower.gif", 0) = False Then '调用一个winsock(0)
           ...
        End If

        If SaveData(DataByte(), "wizenflower.gif", 1) = False Then '再调用一个winsock(1)
           ...
        End If



完整代码如下:
'这是一个支持从网站以HTTP协议下载的模块,支持多线程(WINSOCK)模式。

Private Arrival_First_Times() As Boolean    '数据第一次到达
Private F_Num() As Integer '取得系统的空闲文件号
Public File_Lenth() As String '待下载的文件大小
Public Received_Byte() As Long '已接受字节

Public Function SaveData(DataByte() As Byte, FileName As String, Pros_ID As Integer) As Boolean
'DataByte():接收到的字节数组,FileName:要保存的文件名ros_ID:线程ID,支持多WINSOCK。

'根据线程数定义动态数组的大小(保护原有数据模式)
ReDim Preserve Arrival_First_Times(Pros_ID + 1)
ReDim Preserve F_Num(Pros_ID + 1)
ReDim Preserve File_Lenth(Pros_ID + 1)
ReDim Preserve Received_Byte(Pros_ID + 1)

On Error GoTo err
If Arrival_First_Times(Pros_ID) = False Then '数据第一次到达的时候,包含消息头,也可能一起包括2进制文件:所以检查消息头,并分离数据

        Dim DataStr As String
        DataStr = StrConv(DataByte(), vbUnicode) '这里是将字节数组转化为字符串,以便于操作
   
        If InStr(1, DataStr, "HTTP/1.1 200 OK") Or InStr(1, DataStr, "HTTP/1.0 200 OK") Then '检查http响应状态
             '取得待下载的文件大小字节数
             Dim pos1, pos2, Title_Lenth, Start_Pos
             Title_Lenth = Len("Content-Length:")
             pos1 = InStr(1, DataStr, "Content-Length:")
             pos2 = InStr(pos1, DataStr, vbCrLf)
             File_Lenth(Pros_ID) = Mid(DataStr, pos1 + Title_Lenth, pos2 - pos1 - Title_Lenth)
            
            '从服务器返回的数据中,取得下载文件的起始位置。
            '说明:消息结束和文件结束的地方,分别用2个换行表示数据结束。一个换行vbcrlf占用2字节。
            '在字符串中,2个换行就是2个vbcrlf;而在字节数组中,就是连续的DataByte(i)=13,DataByte(i+1)=10,DataByte(i+2)=13,DataByte(i+3)=10
            
             For i = 0 To UBound(DataByte()) - 3 '减3是因为文件的最后也是2个换行,而我们需要的是消息头和文件之间的分割,所以不搜索最后的那2次换行。
                 If DataByte(i) = 13 And DataByte(i + 1) = 10 And DataByte(i + 2) = 13 And DataByte(i + 3) = 10 Then
                 Start_Pos = i + 4 '加4是因为每个换行占用了2个字节,所以往后4个字节,正好是二进制数据开始的地方
                 Exit For
                 End If
             Next
            
             '将第一次接受到的字节,除去HTTP响应标题以外的二进制数据,写入文件
             If Dir(App.Path & "/" & FileName) <> "" Then '第一次写入文件,如果写入之前文件已存在,则删除。
             Kill App.Path & "/" & FileName
             End If
            
             F_Num(Pros_ID) = FreeFile()
             Open App.Path & "/" & FileName For Binary Lock Write As #F_Num(Pros_ID)
                For i = Start_Pos To UBound(DataByte())
                    Put #F_Num(Pros_ID), , DataByte(i)
                Next
             Close #F_Num(Pros_ID)
            
             Arrival_First_Times(Pros_ID) = True '已经完成第一批到达数据的处理。
            
       Else
            SaveData = False
            Exit Function
       End If
      
       Received_Byte(Pros_ID) = Received_Byte(Pros_ID) + UBound(DataByte()) + 1 - Start_Pos
      
Else '如果不是第一到达数据,则直接写入文件

        F_Num(Pros_ID) = FreeFile()
        Open App.Path & "/" & FileName For Binary Lock Write As #F_Num(Pros_ID)
        If LOF(F_Num(Pros_ID)) > 0 Then Seek #F_Num(Pros_ID), LOF(F_Num(Pros_ID)) + 1
        Put #F_Num(Pros_ID), , DataByte()
        Close #F_Num(Pros_ID)

        Received_Byte(Pros_ID) = Received_Byte(Pros_ID) + UBound(DataByte()) + 1
End If

SaveData = True
Exit Function

err:
SaveData = False

End Function

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一、WinSock简介 Socket(套接字)最初是由加利福尼亚大学Berkeley(伯克利)分校为UNIX操作系统开发的网络通信接口,随着UNIX的广泛使用,Socket成为当前最流行的网络通信应用程序接口之一。20世纪90年代初,由Sun Microsystems,JSB,FTP software,Microdyne和Microsoft等几家公司共同定制了一套标准,即Windows Socket规范,简称WinSock。 VB编写网络程序主要有两种方式:1.winsock控件 2.winsockAPI 二、WinSock控件的使用 1.WinSock控件的主要属性 LocalHostName属性 本地机器名 LocalIP属性 本地机器IP地址 LocalPort属性 本地机器通信程序的端口(0<端口<65536) RemoteHost属性 远程机器名 RemotePort属性 远程机器的通信程序端口 Protocol属性 通过Protocol属性可以设置WinSock控件连接远程计算机使用的协议。可选的协议是TCP和UDP对应的VB的常量分别是sckTCPProtocol和sckUDPProtocol,Winsock控件默认协议是TCP。注意:虽然可以在运行时设置协议,但必须在连接未建立或断开连接后。 SocketHandle属性 返回当前socket连接的句柄,这是只读属性。 RemoteHostIP属性 属性返回远程计算机的IP地址。在客户端,当使用了控件的Connect方法后,远程计算机的IP地址就赋给了RemoteHostIP属性,而在服务器端,当ConnectRequest事件后,远程计算机(客户端)的IP地址就赋给了这个属性。如果使用的是UDP协议那么当DataArrival事件后,发送UDP报文的计算机的IP才赋给了这个属性。 ByteReceived属性 返回当前接收缓冲区中的字节数 State属性 返回WinSock控件当前的状态 常数 值 描述 sckClosed 0 缺省值,关闭。 SckOpen 1 打开。 SckListening 2 侦听 sckConnectionPending 3 连接挂起 sckResolvingHost 4 识别主机。 sckHostResolved 5 已识别主机 sckConnecting 6 正在连接。 sckConnected 7 已连接。 sckClosing 8 同级人员正在关闭连接。 sckError 9   错误 2.WinSock主要方法 Listen方法 方法用于服务器程序,等待客户访问。格式:Winsock对象.listen Connect方法 用于向远程主机发出连接请求。格式:Winsock对象.connect [远程主机IP,远程端口] Accept方法 用于接受一个连接请求。格式:Winsock对象.accept Request ID Senddata方法 用于发送数据。格式:Winsock对象.senddata 数据 Getdata方法 用来取得接收到的数据。格式:Winsock对象.getdata 变量 [,数据类型 [,最大长度]] Close方法 关闭当前连接。格式:Winsock对象.close Bind方法 用Bind方法可以把一个端口号固定为本控件使用,使得别的应用程序不能再使用这个端口。 Listen方法Listen方法只在使用TCP协议时有用。它将应用程序置于监听检测状态。 Connect方法 当本地计算机希望和远程计算机建立连接时,就可以调用Connect方法。Connect方法调用的规范为:Connect RemoteHost,RemotePort Accept方法 当服务器接收到客户端的连接请求后,服务器有权决定是否接受客户端的请求。 SendData方法当连接建立后,要发送数据就可以调用SendData方法,该方法只有一个参数,就是要发送的数据。 GetData方法 当本地计算机接收到远程计算机的数据时,数据存放在缓冲区中,要从缓冲区中取出数据,可以使用GetData方法。GetData方法调用规范如下:GetData
在PB中使用WINSOCK.OCX做双向通信的简单例子----PowerBuilder 一、在窗口中添加WINSOCK控件:   在应用中新开一个窗口,在窗口画板中点击controls-->OLE菜单项,弹出 Insert object窗口,单击Insert control标签,从列表框中双击选定 Microsoft Winsock control,将winsock的图标贴在窗口上。   在程序中该控件名称定为winsock_a(甲方)和winsock_b(乙方)。   二、设置信息输入输出文本框:   在窗口中增加一个按钮cb_1,两个单行文本框sle_1,sle_2,分别用于输入 要发送的字符串和接受对方发送的字符串。   三、设置通讯协议:   WINSOCK控件允许用户以UDP和TCP两种协议中任选一种进行通讯。   1.UDP协议设置:UDP协议是一种无连接的通讯协议,在通讯之前,需要绑 定remotehost和remoteport属性,如果需要双向通讯,还要设置localport属性 。   在甲方(本机地址为:134.1.1.1)窗口的Open事件中加入如下语句: winsock_a.object.protocol=1 //winsock通讯协议设为UDP协议 winsock_a.object.remotehost="134.1.1.2" //对方的ip地址 winsock_a.object.remoteport=6000 //对方的winsock通讯端口号 winsock_a.object.localport=6001 //本机的winsock通讯端口号 winsock_a.object.bind //绑定通讯协议   在乙方(本机地址为:134.1.1.2)窗口的Open事件中加入如下语句: winsock_b.object.protocol=1 //winsock通讯协议设为UDP协议 winsock_b.object.remotehost="134.1.1.1" //对方的ip地址 winsock_b.object.remoteport=6001 //对方的winsock通讯端口号 winsock_b.object.localport=6000 //本机的winsock通讯端口号 winsock_b.object.bin //绑定通讯协议   2.TCP协议设置:TCP协议在通讯前需要进行连接。   在甲方(作为服务器端)窗口的Open事件中加入如下语句: winsock_a.object.protocol=0 //winsock通讯协议设为TCP协议 winsock_a.object.localport=6001 //本机的winsock通讯端口号 winsock_a.listen() //启动监听   在甲方winsock_a控件的Connectionrequest事件中加入如下语句: //接受到对方的连接请求后 if winsock_a.object.state0 then winsock_a.close() end if winsock_a.accept(requestID) //建立直接连接 //requestID是Connectionrequest事件自己的参数   在乙方(作为客户端)窗口的Open事件中加入如下语句: winsock_b.object.protocol=0 //winsock通讯协议设为TCP协议 winsock_b.object.remotehost="134.1.1.2" //对方的ip地址 winsock_b.object.remoteport=6000 //对方的winsock通讯端口号 winsock_b.connect() //发出连接请求   3.无论采用哪种协议,都要在窗口的Close事件中加入如下语句: if winsock_a/*或winsock_b*/.object.state0 then winsock_a.close() end if   否则可能第二次使用时发生异常问题   四、开始通讯   在按钮cb_1(caption属性设为‘发送’)的click事件中加入如下语句: winsock_a/*或winsock_b*/.object.send (sle_1.text)   在winsock_a/*或winsock_b*/控件的dataarrival事件中加入如下语句: //接受到对方数据后 string datastr1 winsock_a/*或winsock_b*/.object.getdata (def datastr1) sle_2.text=datastr1 //将数据字符串显示在文本框中   以上程序实际上体现了聊天器的底层工作原理,稍加修改扩充就可以做成

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值