| 发表于:2007-01-09 17:41:064楼 得分:0 |
谢谢楼上2位,但是我是接受文件啊? 如果小文件,可以接受,但是对于大文件,就接受不全。 另一位朋友的答复: 首先你要明白下载文件的过程机制。我这几天正在写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 | | |
|