http 断点续传
www.diybl.com    时间 : 2011-05-20  作者:匿名   编辑:hawk 点击:  1128 [ 评论 ]
-
-

原理:
1. 打开本地文件fopen,移动文件指针到文件尾fseek
2. 获得文件大小ftell, 格式化HTTP请求头 "Range: bytes=ftell -", 以偏移httpfile指针,实现断点续传
3. 获得要下载的文件,以二进制形式传输,OpenURL
4. 接收数据,防止阻塞PeekMessage 
Sample:

显示代码打印
01 char string[25];

02  CString StrFileName=m_lf;

03  CString StrUrl=m_url;

04  CString sheader;

05  long lStartPos =0;

06

07  //打开本地文件,m_lf 是文件路径,如:C:\\a.mp3

08  FILE *file=NULL;

09  file=fopen(m_lf,"ab");

10  if(file!=NULL)

11  {

12  //移动文件指针到文件尾

13   fseek(file,0,SEEK_END);

14   lStartPos=ftell(file);

15   itoa(lStartPos,string,10);

16   m_byte=string;

17  //格式化请求头,如: 从第 1000 个字节起开始下载:“Range: bytes=999 -”

18   sheader.Format(_T("%sRange: bytes=%d-\r\n"), szHeaders,lStartPos);

19  }

20  else

21  {

22   MessageBox("local file failed!");

23   return;

24  }

25  try{

26  CInternetSession s;

27  CHttpFile *hf=NULL;

28  //获得要下载的文件,以二进制形式传输

29  hf=(CHttpFile*)s.OpenURL(m_url,1,INTERNET_FLAG_TRANSFER_BINARY,sheader,-1 );

30  if(hf!=NULL)

31  {

32  //开始传输数据

33   byte *nbytes = new byte[512];

34   int nReadSize=0;

35   nReadSize=hf->Read(nbytes,512);

36   while( nReadSize >0)

37   {

38    fwrite(nbytes,1,nReadSize,file);

39    nReadSize=hf->Read(nbytes,512);

40    lStartPos=ftell(file);

41    itoa(lStartPos,string,10);

42    m_byte=string;

43 //防止阻塞

44    doenents();

45   }

46

47   fclose(file);

48   hf->Close();

49   delete hf;

50  }

51  }catch(CInternetException *p){

52 //  hf=NULL;

53   p->Delete();

54  }

55 BOOL CGfDlg::doenents()

56 {

57 MSG msg;

58 while(::PeekMessage(&msg,NULL,0,0,PM_NOREMOVE))

59 {

60 if(!AfxGetApp()->PumpMessage())

61 {

62 ::PostQuitMessage(0);

63 return false;

64 }

65 }

66 return true;

67 }

文章出处:飞诺网(www.diybl.com):http://www.diybl.com/course/3_program/c++/cppjs/20090409/164681.html

但是因为当时用了CFile类实现,而不是SDK,所以我不得不重写,重写时断点续传又重新成了问题

1.下载的是文件列表
2.因为效率不再采用分块传输
3.如何记录文件列表与断点值

鉴于我以前做的断点续传,思路被禁固了一样 转不开弯  直到后来KING老大提示才饶过这个弯 其思路如下

1.客户端用CreateFile以OPEN_EXISTING方式打开要下载的文件列表
2.若成功说明有断点文件,则用GetFileSize得到大小做为断点
3若失败说明文件不存在,则创建一个文件

思路是相当简单的,而且一个好处是不用记录断点值  干净利落
文章出处:飞诺网(www.diybl.com):http://www.diybl.com/course/3_program/c++/cppjs/2007114/83747.html

源码: Windows下HTTP方式单线程下载
www.diybl.com    时间 : 2008-03-31  作者:佚名   编辑:本站 点击:  509 [ 评论 ]
-
-
     针对昨天的试验结果,书写了一个HTTP方式单线程下载的小程序,目前尚不支持断点续传。
希望各位看客使劲拍砖~~

原理:套接字发送HTTP GET方式的请求,然后根据HTTP响应,循环接收信息。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <WinSock2.h>
#include <windows.h>
#include "HttpDown.h"

#pragma  comment(lib, "Ws2_32.lib")

/************************************************************************/
/* 全局变量                                                                */
/************************************************************************/
unsigned long g_FiltTotleLen  = 0;    //下载文件总大小
unsigned long g_DownedFileLen = 0;    //已下载文件大小

/************************************************************************/
/* 函数描述:判断某一指定字符串是否为ip地址                             */
/* 返回值:  是则返回0,否则返回-1                                        */
/* 作者:    liuwp                                                        */
/* 创建时间:2008-03-27                                                    */
/* 其他                                                                    */
/************************************************************************/
int IsIpAddrV4Str(char *pstr)
{
    char a[4],b[4],c[4],d[4];
    int num =0;

if ( !pstr)
        return -1;

num = sscanf(pstr,"%3[0-9].%3[0-9].%3[0-9].%3[0-9]",a,b,c,d);

if ( num != 4 )
        return -1;

if ( atoi(a)>255 ||  atoi(b)>255 || atoi(c) > 255 || atoi(d) >255  )
        return -1;

return 0;
}

/************************************************************************/
/* 函数描述:根据下载地址获得HOST、IP等信息                             */
/* 返回值:  成功返回0,失败返回-1                                        */
/* 作者:    liuwp                                                        */
/* 创建时间:2008-03-27                                                    */
/* 其他                                                                    */
/************************************************************************/
int GetDownInfoByUlr(const char *pDownUrl, char *pIpAddr, int *Port
        , char *pGetInfo, int GetLen, char *RetErrorBuf, int ErrorLen)
{
    int RetCode = 0;
    char pUrlTempBuf[1000];
    char pHostInf[500];

memset(pUrlTempBuf, 0, sizeof(pUrlTempBuf));
    memset(pHostInf, 0, sizeof(pHostInf));

//参数判断
    if (!pDownUrl || !pIpAddr || !Port || !pGetInfo || !RetErrorBuf)
        return -1;

//拷贝字符串
    strncpy(pUrlTempBuf, pDownUrl, sizeof(pUrlTempBuf)-1);

//获得HOST起始位置
    char *pHostStart = strstr(pUrlTempBuf, "://");
    if (!pHostStart)
    {
        _snprintf(RetErrorBuf, ErrorLen-1, "给定的下载URL格式错误,应该类似 http://HOST/GET ");
        return -1;
    }

//根据第一个 “/”获得HOST信息
    pHostStart = pHostStart + strlen("://");

char *pHostEnd = strchr(pHostStart, ''/'');
    if (!pHostEnd)
    {   
        _snprintf(RetErrorBuf, ErrorLen-1, "给定的下载URL格式错误,应该类似 http://HOST/GET ");
        return -1;
    }

*pHostEnd = ''\0'';
    _snprintf(pHostInf, sizeof(pHostInf)-1, "%s", pHostStart);

//获得GET信息
    _snprintf(pGetInfo, GetLen-1, "/%s", pHostEnd+1);

//根据HOST信息获得对应的IP和端口
    char *pPortStart = strchr(pHostInf, '':'');
    if (!pPortStart)
    {
        *Port = 80;    //默认为80
    }
    else
    {
        *pPortStart = ''\0'';
        sscanf(pPortStart+1, "%d", Port);
    }

//判断获得地址是否为IP,不是则转换为IP
    RetCode = IsIpAddrV4Str(pHostInf);
    if (RetCode != 0)
    {
        //初始化环境
        WSADATA WSAData;
        WSAStartup(MAKEWORD(2,2),&WSAData);

struct hostent* lpHostEnt = gethostbyname(pHostInf);
        if(lpHostEnt == NULL)
        {
            _snprintf(RetErrorBuf, ErrorLen-1, "获得域名对应的IP地址失败, GetLastError()=%d", GetLastError());
            return -1;
        }
        else
        {   
            LPSTR lpaddr = lpHostEnt->h_addr_list[0];
            if(lpaddr)
            {
                struct in_addr inAddr;
                memcpy (&inAddr, lpaddr, 4);

sprintf(pIpAddr, "%s", inet_ntoa (inAddr) );
            }
        }

//清除环境
        WSACleanup();
   
    }
    else
    {
        sprintf(pIpAddr, "%s", pHostInf );
    }

return 0;
}

/************************************************************************/
/* 函数描述:通过HTTP协议进行下载                                       */
/* 返回值:  下载成功返回0,失败返回-1                                 */
/* 作者:    liuwp                                                        */
/* 创建时间:2008-03-27                                                    */
/* 其他                                                                    */
/************************************************************************/
int DownByHttpFun(const char *pDownUrl, const char *pDownFile, unsigned long *pTotleLen
               , char *RetErrorBuf, int ErrorLen)
{
    WSADATA WSAData;
    sockaddr_in ServerAddr;
    fd_set fdset;
    struct timeval tv;
    HANDLE hFileHandle = NULL;
    bool FirstFlag = true;
    int RetCode = 0;
    int WriteLen = 0;   
    char SendBuf[1000];
    char RecvBuf[4096];
    char IpAddr[30];
    char GetInfo[600];
    int Port = 0;
    char *pConLen = NULL;
    DWORD dwFileSize  = 0;

memset(IpAddr, 0, sizeof(IpAddr));
    memset(GetInfo, 0, sizeof(GetInfo));
    memset(RecvBuf, 0, sizeof(RecvBuf));
    memset(SendBuf, 0, sizeof(SendBuf));
   
    if (!pDownUrl || !pDownFile || !pTotleLen || !RetErrorBuf)
    {   
        _snprintf(RetErrorBuf, ErrorLen-1, "给定参数不正确");
        return -1;
    }

//根据下载地址获得HOST, GET, IP,端口等信息
    RetCode = GetDownInfoByUlr(pDownUrl, IpAddr,  &Port
        , GetInfo, sizeof(GetInfo)-1, RetErrorBuf, ErrorLen);
    if (RetCode != 0)
        return -1;

//初始化环境
    WSAStartup(MAKEWORD(2,2),&WSAData);
   
    //创建套接字
    SOCKET Sock = socket(AF_INET, SOCK_STREAM, 0);
    if ( SOCKET_ERROR == Sock )
    {
        _snprintf(RetErrorBuf, ErrorLen-1, "创建套接字失败, GetLastError()= %d !", GetLastError());
        goto LEXIT;
    }
   
    //给定服务器地址
    ServerAddr.sin_family = AF_INET;
    ServerAddr.sin_addr.s_addr = inet_addr(IpAddr);
    ServerAddr.sin_port = htons(Port);
   
    //连接服务器
    RetCode = connect(Sock, (struct sockaddr *)&ServerAddr, sizeof(ServerAddr));
    if (RetCode == SOCKET_ERROR)
    {
        _snprintf(RetErrorBuf, ErrorLen-1, "连接服务器失败, GetLastError()= %d !", GetLastError());
        goto LEXIT;
    }
   
    //发送信息
    _snprintf(SendBuf, sizeof(SendBuf)-1
        , "GET %s HTTP/1.1\r\nHost: %s:%d\r\n\r\n"
        ,GetInfo, IpAddr, Port);
   
    RetCode = send(Sock, SendBuf, strlen(SendBuf), 0);
    if (RetCode < 0)
    {
        _snprintf(RetErrorBuf, ErrorLen-1, "发送数据失败, GetLastError()= %d !", GetLastError());
       
        closesocket(Sock);
        WSACleanup();

goto LEXIT;
       
    }
   
    //接收信息
    FD_ZERO(&fdset);
    FD_SET(Sock, &fdset);
    tv.tv_sec = 2*60;    //秒
    tv.tv_usec = 0;

//打开文件
    hFileHandle = CreateFile(pDownFile, GENERIC_WRITE, 0
        , (LPSECURITY_ATTRIBUTES) NULL,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,(HANDLE) NULL);
    if (hFileHandle == INVALID_HANDLE_VALUE)
    {
        _snprintf(RetErrorBuf, ErrorLen-1, "打开文件%s失败, GetLastError()= %d !"
            , pDownFile, GetLastError());

goto LEXIT;
    }

//置空全局变量
    g_FiltTotleLen  = 0;    //下载文件总大小
    g_DownedFileLen = 0;    //已下载文件大小
   
    while(1)
    {
        memset(RecvBuf, 0, sizeof(RecvBuf));
        int len = select(0, &fdset, NULL, NULL, &tv);
        if (len < 1)
        {
            break;
        }
       
        //套接字接收信息
        len = recv(Sock, RecvBuf, sizeof(RecvBuf)-1 ,0);
        if (len <= 0)
        {   
            break;
        }
        
        if (!FirstFlag)    //不是第一次,追加写
        {
            dwFileSize = GetFileSize(hFileHandle, NULL);
            SetFilePointer(hFileHandle, dwFileSize, NULL, FILE_BEGIN);
            RetCode = WriteFile(hFileHandle, RecvBuf, len , (DWORD*)&WriteLen, NULL);
            if (RetCode == 0)
            {
                _snprintf(RetErrorBuf, ErrorLen-1, "写入文件失败 ! GetLastError()= %d !", GetLastError());
                goto LEXIT;
            }

//获得此时已经下载的文件大小
            g_DownedFileLen = dwFileSize + len;
           
            //如果已经下载完毕,则跳出
            if (g_DownedFileLen == *pTotleLen)
                break;
           
            continue;
        }

//判断返回值
        int RetCode =  0;
        sscanf(RecvBuf+strlen("HTTP/1.1 "), "%d", &RetCode);
        if (RetCode < 200 || RetCode > 300)
        {
            _snprintf(RetErrorBuf, ErrorLen-1, "下载失败, 服务器返回码为%d !", RetCode);
            goto LEXIT;
        }

//获得总大小
        pConLen = strstr(RecvBuf, "\r\nContent-Length:");
        if (!pConLen)
        {
            _snprintf(RetErrorBuf, ErrorLen-1, "HTTP协议中未给定文件的大小!");
            goto LEXIT;
        }

sscanf(pConLen, "\r\nContent-Length: %ld\r\n", pTotleLen);
        g_FiltTotleLen = *pTotleLen;
   
        char *pEnd = strstr(RecvBuf, "\r\n\r\n");
        if (!pEnd)
        {
            break;
        }
       
        pEnd = pEnd + strlen("\r\n\r\n");

//移动到文件尾部,写文件
        dwFileSize = GetFileSize(hFileHandle, NULL);
        SetFilePointer(hFileHandle, dwFileSize, NULL, FILE_BEGIN);
        RetCode = WriteFile(hFileHandle, pEnd, len-(pEnd-RecvBuf) , (DWORD*)&WriteLen, NULL);
        if (RetCode == 0)
        {
            _snprintf(RetErrorBuf, ErrorLen-1, "写入文件失败 ! GetLastError()= %d !", GetLastError());
            goto LEXIT;
        }

//获得此时已经下载的文件大小
        g_DownedFileLen = dwFileSize + len - (pEnd - RecvBuf);
       
        //更改第一次接收标识
        FirstFlag = false;
       
    }

//下载完毕,判断下载大小是否相同
    dwFileSize = GetFileSize(hFileHandle, NULL);
    if (pTotleLen && *pTotleLen != 0 && *pTotleLen != dwFileSize)
    {
        _snprintf(RetErrorBuf, ErrorLen-1, "下载文件不完整, 请重新下载!");
        goto LEXIT;
    }
   
    //关闭文件
    if (hFileHandle)
    {
        CloseHandle(hFileHandle);
        hFileHandle = NULL;   
    }

//关闭套接字
    if (Sock != 0)
    {
        closesocket(Sock);
        Sock = 0;
    }
   
    //清除环境
    WSACleanup();
   
    return 0;

LEXIT:

//关闭文件
    if (hFileHandle)
    {
        CloseHandle(hFileHandle);
        hFileHandle = NULL;   
    }

//关闭套接字
    if (Sock != 0)
    {
        closesocket(Sock);
        Sock = 0;
    }
   
    //清除环境
    WSACleanup();
   
    return -1;

}

/************************************************************************/
/* 函数描述:获得文件下载的相关信息                                     */
/* 返回值:                                                                */
/* 作者:    liuwp                                                        */
/* 创建时间:2008-03-28                                                    */
/* 其他                                                                    */
/************************************************************************/
float GetDownloadRate(unsigned long *pTotleLen , unsigned long *pDownLen)
{
    float DownRate = 0;

if (!pTotleLen || !pTotleLen )
        return 0;

//获得文件总大小和已下载的大小
    *pTotleLen = g_FiltTotleLen;
    *pDownLen = g_DownedFileLen;

//计算速率
    if (g_FiltTotleLen == 0)
        return 0;

if (g_DownedFileLen == 0)
        return 0;

DownRate = (float)g_DownedFileLen/(float)g_FiltTotleLen;

return DownRate;
}

文章出处:飞诺网(www.diybl.com):http://www.diybl.com/course/3_program/c++/cppjs/2008331/107753.html

转载于:https://www.cnblogs.com/Ray-chen/archive/2011/12/14/2287959.html

http 断点续传,Windows下HTTP方式单线程下载相关推荐

  1. windows下基于Aria2的下载工具

    windows下基于Aria2的下载工具 Motrix https://motrix.app/ https://www.iplaysoft.com/motrix.html Photon https:/ ...

  2. Windows下SSH客户端的下载

    Windows下SSH客户端的下载 因为SSH远程操作涉及自己的电脑安全,建议在如下官网免费下载 1.putty: http://www.chiark.greenend.org.uk/~sgtatha ...

  3. Mysql5.7 windows 下压缩包方式安装以及环境配置

    文章目录 写在前面 一.下载mysql压缩包 二.配置环境变量与安装mysql服务 三.修改mysql密码 写在前面 由于电脑重装,所需要的软件和环境需要重新配置,mysql虽然经常会用到,但是配置和 ...

  4. Windows下的Apache的下载与安装

    PHP的运行必然少不了服务器的支持,何为服务器?通俗讲就是在一台计算机上,安装个服务器软件,这台计算机便可以称之为服务器,服务器软件和计算机本身的操作系统是两码事,计算机自身的操作系统可以为linux ...

  5. Windows 下使用 BaiduExporter + Aria2 下载百度网盘文件

    百度盘下载限速,Aria2 可以明显加大下载速度,最近研究了一下如何在 Windows 下使用 Aria2,需要以下三个工具配合使用: BaiduExporter:百度云盘导出下载的 Chrome 插 ...

  6. Windows下Zeal文档下载问题

    目录 一.Zeal 二.步骤 一.Zeal 一款为软件开发者提供的离线文档浏览器,目前支持Linux和Windows.可下载多种编程语言或软件工具的帮助文档.下载:https://zealdocs.o ...

  7. Windows 下noinstall方式安装 mysql-5.7.5-m15-winx64

    下载解压不说 我解压在:E:\DBFiles\mysql-5.7.15-winx64\mysql-5.7.15-winx64 添加配置文件E:\DBFiles\mysql-5.7.15-winx64\ ...

  8. Windows下mysql数据库的下载、安装、使用(详细)(有后续)

    一.下载MySQL 下载地址:https://dev.mysql.com/downloads/mysql/ 从第一步的页面往下滑,找到下面的位置---------------------------- ...

  9. Windows下Postgresql数据库的下载与配置

    本文方法介绍的是windows系统中postgresql二进制压缩包的安装及配置.下载地址:下载地址 执行下列步骤前,暂作以下假定: PostgreSQL拟装在d:\postgresql 数据库以后拟 ...

最新文章

  1. 9.Spring Security添加记住我功能
  2. c语言 offsetof函数,C 库宏 - offsetof()函数
  3. 应用Rational 工具简化基于J2EE的项目(二)启动项目
  4. 快速实现一个Http回调组件
  5. 分享30个新鲜PSD网站模板免费下载
  6. 华为拿百亿资金给员工分红,预计每股1.58元
  7. 洛谷 [P2964] 硬币的游戏
  8. javascript学习之数组的使用二 forEach方法
  9. Mysql查询语句使用select.. for update导致的数据库死锁分析
  10. eclipse搭建springmvc
  11. Unity Editor 查找资源依赖、反向查找资源依赖Dependencies
  12. 7月1日天刀服务器维护,天涯明月刀7月1日满级新服_天刀满级新服天命风流入君怀_3DM网游...
  13. vv7无法启动显示发动机故障_启动系统故障引起的发动机无法启动诊断方法
  14. 思科模拟器启用CHAP协议
  15. 给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false
  16. 在工业生产安全管理中,人员定位系统能做什么?
  17. 高通MSM8909:LCD hx8394d驱动调试
  18. 2. Switch能否用String做参数?
  19. pikachu靶场-5 远程命令,代码执行漏洞(RCE)
  20. 麦香牛肉(dp 、数论)

热门文章

  1. github怎么切换到gitee_AOSP-RISCV 的开源仓库在 Gitee 上新建了镜像
  2. mysql密码命名规则_MySql命名规范
  3. mysql5.7解压版错误_mysql 5.7 解压版 安装net start mysql 发生系统错误 2
  4. gjr garch Matlab,基于Copula-ARIMA-GJR-GARCH模型的股票指数相关性分析
  5. 杭州软件测试培训有用吗,杭州软件测试培训靠谱吗
  6. oracle 12 ORA-01262,oracle物理dg安装:方法二
  7. leetcode181. 超过经理收入的员工(SQL)
  8. TensorFlow(3)-与训练相关的操作
  9. 在wsl下运行c语言,在Windows10通过WSL架设linux/gcc c语言学习环境
  10. 密码学 专题 DH密钥交换算法