TCP+HTTP实现了断点续传

微信公众号:小浩笔记

什么是断点续传?

断点续传,在我们生活中起了很大作用,也帮我们节省了很多时间,就是信号中断后(掉线或关机等),下次能够从上次的地方接着传送(一般指下载或上传),不支持断点续传就意味着下次下载或上传必须从零开始.

举个简单的例子:迅雷上次没传完,下次打开,就可以直接传了。


解决方案:

下载:多次握手,首先得到断点续传的起始位置,然后打开文件读取偏移量,从断点续传位置开始上传。写文件的时候要用追加模式;

上传:S端记录上次传的记录,下次C上传的时候,问下S上传到哪了,C就从上次传的偏移量,读文件继续上传;

而小浩做的笔记内容就是从网上下载图片,中途断开,然后再连接,是否完成下载;实现此功能,运用了TCP、HTTP等知识点。


来吧,一笔一笔来做笔记...

1.首先,要准备图片的链接,然后从链接获取主机名和文件名

/*******************************
参数
link:图片链接
host:主机名
pathname文件名
********************************/
void argParser(const char *link, char **host, char **pathname)
{
    // link : "http://www.baidu.com/xxx/yyy/3453453425.jpg";

    char *h, *p;
    h = p = link;

    char *delim1 = "http://";
    char *delim2 = "https://";
    if(strstr(link, delim1) != NULL)
    {
        h += strlen(delim1);
    }
    else if(strstr(link, delim2) != NULL)
    {
        h += strlen(delim2);
    }

    p = strstr(h, "/");
    if(p == NULL)
    {
        printf("非法连接!\n");
        exit(0);
    }

    *host = calloc(1, 256);
    *pathname = calloc(1, 1024);

    memcpy(*host, h, p-h);
    memcpy(*pathname, p, strlen(p));
}

 

2.获取服务器IP,然后使用套接字连接服务器

// 获取服务器I
    struct hostent * he = gethostbyname(host);
    struct in_addr serverIP = *(struct in_addr*)he->h_addr_list[0];

    int sockfd = Socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in addr;
    socklen_t len = sizeof(addr);
    addr.sin_family = AF_INET;
    addr.sin_addr = serverIP;
    addr.sin_port = htons(80);

    Connect(sockfd, (struct sockaddr *)&addr, len);
    printf("连接成功!\n");

 

3.(断点续传来了....)准备好本地文件,判断文件释放已经下载过,然后将文件的缓冲类型设置为不缓冲,提前谈一谈,主要是begin这个变量,如果文件已经下载过,获取该文件的大小,使写的光标偏移的文本,然后也使读端(即读图片),使光标偏移到断开下载的地方。

// 准备好本地文件
    char *filename = strrchr(pathname, '/')+1;

    // 判断文件释放已经下载过
    FILE *fp = NULL;
    long begin = 0;
    if(access(filename, F_OK))
        fp = fopen(filename, "w");
    else
    {
        struct stat fileinfo;
        bzero(&fileinfo, sizeof(fileinfo));
        stat(filename, &fileinfo);

        begin = fileinfo.st_size;
        fp = fopen(filename, "a");
    }

    // 将文件的缓冲类型设置为不缓冲
    setvbuf(fp, NULL, _IONBF, 0);

4.发送HTTP请求(begin这个变量也发过去了),然后收到响应头部,然后分析响应头部,获取内容大小

// 发送HTTP请求
char *httpRequest = calloc(1, 2048);
snprintf(httpRequest, 2048, "GET %s HTTP/1.1\r\n"
              "Host: %s\r\n"
              "Range: bytes=%d-\r\n"
              "\r\n", pathname, host, begin);

write(sockfd, httpRequest, strlen(httpRequest));

// 接收响应头部
char *httpResponse = calloc(1, 2048);
int total = 0;
while(1)
{
    total += read(sockfd, httpResponse+total, 1);

    if(strstr(httpResponse, "\r\n\r\n"))
         break;
}
printf("响应头部:\n%s", httpResponse);

long length = getLen(httpResponse);
printf("即将要下载的大小:%d\n", length);

5.然后接受响应正文,把图片从断点下载下来,完璧归赵。

// 接收响应正文
    char *content;
    content = calloc(1, 10*1024);

    total = 0;
    total += begin;
    while(length > 0)
    {
        bzero(content, 10*1024);
        int n = read(sockfd, content, 10*1024);

        fwrite(content, n, 1, fp);
        length -= n;
        total += n;

        printf("已经下载: %d【字节】\r", total);
    }

这个断点续传下载图片的基本框架就是这样子了。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值