Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1029316
  • 博文数量: 177
  • 博客积分: 3629
  • 博客等级: 中校
  • 技术积分: 1839
  • 用 户 组: 普通用户
  • 注册时间: 2005-02-23 21:21
文章分类

全部博文(177)

文章存档

2021年(1)

2020年(5)

2019年(4)

2018年(7)

2017年(1)

2016年(4)

2014年(1)

2013年(8)

2012年(10)

2011年(50)

2009年(12)

2008年(10)

2006年(56)

2005年(8)

分类: C/C++

2006-04-10 16:31:28

使用比HttpSocket更简单.
 
在HttpSocket基础上改的例子,也是下载一个URL文件,不过这儿更简单,只需要URL和文件名就可以得到了.
 
#include
#include
#include
using namespace std;
class MyHttp : public HttpGetSocket
{
public:
 MyHttp(SocketHandler& h,string url,string filename): HttpGetSocket(h,url,filename) {}
};
int main()
{
 SocketHandler h;
 MyHttp Get(h,"http://www.cublog.cn/u/4466/?u=http://www.cublog.cn/u/4466/showart.php?id=97754","cublog.html");
 h.Add(&Get);
 h.Select(1,0);
 while(h.GetCount()){
  h.Select(1,0);
 }
 
}
 
理解一下:
在HttpSocket类的基础上,HttpGetSocket重载了
OnHeader()
OnFirst()
OnContent()
OnConnect()
OnDelete()
OnHeaderComplete()
OnData()
这几个函数.
OnHeaderComplete()函数有意思,当HTTP头文件传输完后,这个函数被除数调用,它检查内定的文件名变量是否被赋值,如果已被赋值,它将自动打开一个可写文件,以二进制模式,把文件指针保存起来.
HttpSocket类里说过,OnData函数能接收HTTP实体部分.这儿也一样.只不过多了个OnContent的调用.在OnContent里检查文件指针是否有效,如有效则把数据写入此文件.
OnDelete函数里也有对OnContent的调用,保存一下已收到的数据这也是一个机会.
 
辅助函数
url_this,url这两个函数是把URL解析为内定变量,如host,port,file等.
 
SetDataPtr(),GetDataPtr()是设置缓冲区的,可以自己指定,也可以不指定.
不指定时会自动创建一个.无须费心.可以参考OnHeader一节
 
如果自己想处理细节,还是用HttpSocket类.看来看去,HttpGetSocket都是为了下载文件准备的,如果不用这个功能,不如直接用HttpSocket和TcpSocket.
 
由于HttpGetSocket下载大文件时会占用大量内存,如果下载200M的还可以接受,如果1G的话就不可想象了.下面是偶改的代码:下载208M的文件也只用10M以内的内存.
 
新加变量:
size_t m_minLimitOfWrite; ///< 这是偶自定的变量,到了1024*1024以上就写入文件并归零变量
 
修改OnData函数如下:
//只需设一个很小的自定义缓冲区,便会使 m_content_ptr + len > m_data_max 条件为真,从而避开memcpy.
void HttpGetSocket::OnData(const char *buf,size_t len)
{             //缓冲区iBuf已经接收了数据,把指针传过来,如果不是为了兼容原代码,这儿直接写文件即可.有些代码可删.
 if (m_content_ptr + len > m_data_max)
 {
  Handler().LogError(this, "OnData", -1, "content buffer overflow", LOG_LEVEL_ERROR);
 }
 else
 {     //如果缓冲区太小不能容纳大量数据,则不写入缓冲区,直接写入文件.可以设一个小缓冲区避开memcpy
  memcpy(m_data + m_content_ptr, buf, len);
 }     //如果我需要buf中的内容,直接重载OnData即可,这儿copy一下,内存利用不好
 if (m_fil)
 {
  fwrite(buf,1,len,m_fil);
 }
 m_content_ptr += len;
 m_minLimitOfWrite += len;
 if (m_content_length > 0 && (m_minLimitOfWrite>=(1024*1024) || m_content_ptr== m_content_length))
 {      //自定义的 m_minLimitOfWrite>=(1024*1024) 使接收到1M字节就写入文件,对于大文件尤其重要
  OnContent();
  m_minLimitOfWrite =0;
 }
}
修改OnContent函数如下:
void HttpGetSocket::OnContent()  //在OnData中被调用,
{
 if (m_fil)
 {
  fflush(m_fil);                 //写入文件,只有HTTP实体部分
  if(m_content_ptr!= m_content_length) //这是偶加的,不收完继续,收完关闭文件
   return;
  fclose(m_fil);
 }
 m_fil = NULL;
 SetCloseAndDelete(true);
 m_bComplete = true;
}
使用时如下:
unsigned char buf[1];
...
HttpGetSocket get(.....);
get.SetDataPtr(buf,1);
 
用一个小缓冲区避开HttpGetSocket分配和下载文件一样大小的缓冲区.因为有了ibuf的缓冲区,所以我们不设自己的了,直接写入文件即可.
如果分配了缓冲区,还要从ibuf里往我们的缓冲区里copy,不知道原作者怎么考虑的?期待有人能给偶个解答.
哪天查查英语词典,上官方网发贴问一下.
 
猜想一下,如果不考虑大文件的话,仅对网页文件,原代码的效果还是很好的.空间换时间?偶不知道.
 
阅读(1721) | 评论(2) | 转发(0) |
0

上一篇:Socket库尝试之六

下一篇:VC6和WTL的故事

给主人留下些什么吧!~~