利用stream实现一个简单的http下载器

其实这个http下载器的功能已经相当完善了,支持:限速、post投递和上传、自定义http header、设置user agent、设置range和超时

而且它还不单纯只能下载http,由于使用了stream,所以也支持其他协议,你也可以用它来进行文件之间的copy、纯tcp下载等等。。

完整demo请参考:https://github.com/waruqi/tbox/wiki

stream.c

/* //////////////////////////////////////////////////////////////////////////////////////
 * includes
 */
#include "../demo.h"

/* //////////////////////////////////////////////////////////////////////////////////////
 * types
 */
typedef struct __tb_demo_context_t
{
  // verbose
  tb_bool_t      verbose;

}tb_demo_context_t;

/* //////////////////////////////////////////////////////////////////////////////////////
 * func
 */
#ifdef TB_CONFIG_MODULE_HAVE_OBJECT
static tb_bool_t tb_demo_http_post_func(tb_size_t state, tb_hize_t offset, tb_hong_t size, tb_hize_t save, tb_size_t rate, tb_cpointer_t priv)
{
  // percent
  tb_size_t percent = 0;
  if (size > 0) percent = (tb_size_t)((offset * 100) / size);
  else if (state == TB_STATE_CLOSED) percent = 100;

  // trace
  tb_trace_i("post: %llu, rate: %lu bytes/s, percent: %lu%%, state: %s", save, rate, percent, tb_state_cstr(state));

  // ok
  return tb_true;
}
static tb_bool_t tb_demo_stream_head_func(tb_char_t const* line, tb_cpointer_t priv)
{
  tb_printf("response: %s\n", line);
  return tb_true;
}
static tb_bool_t tb_demo_stream_save_func(tb_size_t state, tb_hize_t offset, tb_hong_t size, tb_hize_t save, tb_size_t rate, tb_cpointer_t priv)
{
  // check
  tb_demo_context_t* context = (tb_demo_context_t*)priv;
  tb_assert_and_check_return_val(context, tb_false);

  // print verbose info
  if (context->verbose)
  {
    // percent
    tb_size_t percent = 0;
    if (size > 0) percent = (tb_size_t)((offset * 100) / size);
    else if (state == TB_STATE_CLOSED) percent = 100;

    // trace
    tb_printf("save: %llu bytes, rate: %lu bytes/s, percent: %lu%%, state: %s\n", save, rate, percent, tb_state_cstr(state));
  }

  // ok
  return tb_true;
}

/* //////////////////////////////////////////////////////////////////////////////////////
 * globals
 */
static tb_option_item_t g_options[] =
{
  {'-',  "gzip",     TB_OPTION_MODE_KEY,     TB_OPTION_TYPE_BOOL,    "enable gzip"        }
,  {'-',  "no-verbose",  TB_OPTION_MODE_KEY,     TB_OPTION_TYPE_BOOL,    "disable verbose info"   }
,  {'d',  "debug",    TB_OPTION_MODE_KEY,     TB_OPTION_TYPE_BOOL,    "enable debug info"     }
,  {'k',  "keep-alive",  TB_OPTION_MODE_KEY,     TB_OPTION_TYPE_BOOL,    "keep alive"        }
,  {'h',  "header",    TB_OPTION_MODE_KEY_VAL,   TB_OPTION_TYPE_CSTR,    "the custem http header"  }
,  {'-',  "post-data",  TB_OPTION_MODE_KEY_VAL,   TB_OPTION_TYPE_CSTR,    "set the post data"     }
,  {'-',  "post-file",  TB_OPTION_MODE_KEY_VAL,   TB_OPTION_TYPE_CSTR,    "set the post file"     }
,  {'-',  "range",    TB_OPTION_MODE_KEY_VAL,   TB_OPTION_TYPE_CSTR,    "set the range"       }
,  {'-',  "timeout",   TB_OPTION_MODE_KEY_VAL,   TB_OPTION_TYPE_INTEGER,   "set the timeout"      }
,  {'-',  "limitrate",  TB_OPTION_MODE_KEY_VAL,   TB_OPTION_TYPE_INTEGER,   "set the limitrate"     }
,  {'h',  "help",     TB_OPTION_MODE_KEY,     TB_OPTION_TYPE_BOOL,    "display this help and exit"}
,  {'-',  "url",     TB_OPTION_MODE_VAL,     TB_OPTION_TYPE_CSTR,    "the url"          }
,  {'-',  tb_null,    TB_OPTION_MODE_MORE,    TB_OPTION_TYPE_NONE,    tb_null           }

};

/* //////////////////////////////////////////////////////////////////////////////////////
 * main
 */
tb_int_t tb_demo_stream_main(tb_int_t argc, tb_char_t** argv)
{
  // done
  tb_option_ref_t   option = tb_null;
  tb_stream_ref_t   istream = tb_null;
  tb_stream_ref_t   ostream = tb_null;
  tb_stream_ref_t   pstream = tb_null;
  do
  {
    // init option
    option = tb_option_init("stream", "the stream demo", g_options);
    tb_assert_and_check_break(option);

    // done option
    if (tb_option_done(option, argc - 1, &argv[1]))
    {
      // debug & verbose
      tb_bool_t debug = tb_option_find(option, "debug");
      tb_bool_t verbose = tb_option_find(option, "no-verbose")? tb_false : tb_true;

      // done url
      if (tb_option_find(option, "url"))
      {
        // init istream
        istream = tb_stream_init_from_url(tb_option_item_cstr(option, "url"));
        tb_assert_and_check_break(istream);

        // ctrl http
        if (tb_stream_type(istream) == TB_STREAM_TYPE_HTTP)
        {
          // enable gzip?
          if (tb_option_find(option, "gzip"))
          {
            // auto unzip
            if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_AUTO_UNZIP, 1)) break;

            // need gzip
            if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD, "Accept-Encoding", "gzip,deflate")) break;
          }

          // enable debug?
          if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD_FUNC, debug? tb_demo_stream_head_func : tb_null)) break;

          // custem header?
          if (tb_option_find(option, "header"))
          {
            // init
            tb_string_t key;
            tb_string_t val;
            tb_string_init(&key);
            tb_string_init(&val);

            // done
            tb_bool_t      k = tb_true;
            tb_char_t const*  p = tb_option_item_cstr(option, "header");
            while (*p)
            {
              // is key?
              if (k)
              {
                if (*p != ':' && !tb_isspace(*p)) tb_string_chrcat(&key, *p++);
                else if (*p == ':')
                {
                  // skip ':'
                  p++;

                  // skip space
                  while (*p && tb_isspace(*p)) p++;

                  // is val now
                  k = tb_false;
                }
                else p++;
              }
              // is val?
              else
              {
                if (*p != ';') tb_string_chrcat(&val, *p++);
                else
                {
                  // skip ';'
                  p++;

                  // skip space
                  while (*p && tb_isspace(*p)) p++;

                  // set header
                  if (tb_string_size(&key) && tb_string_size(&val))
                  {
                    if (debug) tb_printf("header: %s: %s\n", tb_string_cstr(&key), tb_string_cstr(&val));
                    if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD, tb_string_cstr(&key), tb_string_cstr(&val))) break;
                  }

                  // is key now
                  k = tb_true;

                  // clear key & val
                  tb_string_clear(&key);
                  tb_string_clear(&val);
                }
              }
            }

            // set header
            if (tb_string_size(&key) && tb_string_size(&val))
            {
              if (debug) tb_printf("header: %s: %s\n", tb_string_cstr(&key), tb_string_cstr(&val));
              if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD, tb_string_cstr(&key), tb_string_cstr(&val))) break;
            }

            // exit
            tb_string_exit(&key);
            tb_string_exit(&val);
          }

          // keep alive?
          if (tb_option_find(option, "keep-alive"))
          {
            if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_HEAD, "Connection", "keep-alive")) break;
          }

          // post-data?
          if (tb_option_find(option, "post-data"))
          {
            tb_char_t const*  post_data = tb_option_item_cstr(option, "post-data");
            tb_hize_t      post_size = tb_strlen(post_data);
            if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_METHOD, TB_HTTP_METHOD_POST)) break;
            if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_POST_DATA, post_data, post_size)) break;
            if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_POST_FUNC, tb_demo_http_post_func)) break;
            if (debug) tb_printf("post: %llu\n", post_size);
          }
          // post-file?
          else if (tb_option_find(option, "post-file"))
          {
            tb_char_t const* url = tb_option_item_cstr(option, "post-file");
            if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_METHOD, TB_HTTP_METHOD_POST)) break;
            if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_POST_URL, url)) break;
            if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_POST_FUNC, tb_demo_http_post_func)) break;
            if (debug) tb_printf("post: %s\n", url);
          }
        }

        // set range
        if (tb_option_find(option, "range"))
        {
          tb_char_t const* p = tb_option_item_cstr(option, "range");
          if (p)
          {
            // the bof
            tb_hize_t eof = 0;
            tb_hize_t bof = tb_atoll(p);
            while (*p && tb_isdigit(*p)) p++;
            if (*p == '-')
            {
              p++;
              eof = tb_atoll(p);
            }
            if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_HTTP_SET_RANGE, bof, eof)) break;
          }
        }

        // set timeout
        if (tb_option_find(option, "timeout"))
        {
          tb_size_t timeout = tb_option_item_uint32(option, "timeout");
          if (!tb_stream_ctrl(istream, TB_STREAM_CTRL_SET_TIMEOUT, timeout)) break;
        }

        // print verbose info
        if (verbose) tb_printf("open: %s: ..\n", tb_option_item_cstr(option, "url"));

        // open istream
        if (!tb_stream_open(istream))
        {
          // print verbose info
          if (verbose) tb_printf("open: %s\n", tb_state_cstr(tb_stream_state(istream)));
          break;
        }

        // print verbose info
        if (verbose) tb_printf("open: ok\n");

        // init ostream
        if (tb_option_find(option, "more0"))
        {
          // the path
          tb_char_t const* path = tb_option_item_cstr(option, "more0");

          // init
          ostream = tb_stream_init_from_file(path, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_BINARY | TB_FILE_MODE_TRUNC);

          // print verbose info
          if (verbose) tb_printf("save: %s\n", path);
        }
        else
        {
          // the name
          tb_char_t const* name = tb_strrchr(tb_option_item_cstr(option, "url"), '/');
          if (!name) name = tb_strrchr(tb_option_item_cstr(option, "url"), '\\');
          if (!name) name = "/stream.file";

          // the path
          tb_char_t path[TB_PATH_MAXN] = {0};
          if (tb_directory_curt(path, TB_PATH_MAXN))
            tb_strcat(path, name);
          else break;

          // init file
          ostream = tb_stream_init_from_file(path, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_BINARY | TB_FILE_MODE_TRUNC);

          // print verbose info
          if (verbose) tb_printf("save: %s\n", path);
        }
        tb_assert_and_check_break(ostream);

        // the limit rate
        tb_size_t limitrate = 0;
        if (tb_option_find(option, "limitrate"))
          limitrate = tb_option_item_uint32(option, "limitrate");

        // save it
        tb_hong_t      save = 0;
        tb_demo_context_t  context = {0};
        context.verbose   = verbose;
        if ((save = tb_transfer_done(istream, ostream, limitrate, tb_demo_stream_save_func, &context)) < 0) break;
      }
      else tb_option_help(option);
    }
    else tb_option_help(option);

  } while (0);

  // exit pstream
  if (pstream) tb_stream_exit(pstream);
  pstream = tb_null;

  // exit istream
  if (istream) tb_stream_exit(istream);
  istream = tb_null;

  // exit ostream
  if (ostream) tb_stream_exit(ostream);
  ostream = tb_null;

  // exit option
  if (option) tb_option_exit(option);
  option = tb_null;

  return 0;
}
#else
tb_int_t tb_demo_stream_main(tb_int_t argc, tb_char_t** argv)
{
  return 0;
}
#endif

以上所述就是本文的全部内容了,希望大家能够喜欢。

(0)

相关推荐

  • login.exe HGFS木马下载器的手动查杀方法

    样本信息:File: login.exe Size: 25428 bytes Modified: 2008年4月25日, 16:30:08 MD5: 9777E8C79312F2E3D175AA1F64B07C11 SHA1: 4236D76C4FAEFE1CDF22414A25E946E493E0D52E CRC32: 5A562203 1.病毒初始化:创建互斥量HGFSMUTEX,保证系统内只有一个实例在运行 2.释放如下文件或者副本 %systemroot%\system32\Autoru

  • Python制作CSDN免积分下载器

    CSDN免积分下载 你懂的. 1.输入资源地址如:http://download.csdn.net/download/gengqkun/4127808 2.输入验证码 3.点击下载,会弹出浏览器下载. 注:成功率在70-80% ,界面很丑,请将就着用. 复制代码 代码如下: #-*-coding:utf-8-*- #python3.3.5 import urllib.parse,urllib.request,http.cookiejar,io,webbrowser import tkinter

  • Android编程开发实现多线程断点续传下载器实例

    本文实例讲述了Android编程开发实现多线程断点续传下载器.分享给大家供大家参考,具体如下: 使用多线程断点续传下载器在下载的时候多个线程并发可以占用服务器端更多资源,从而加快下载速度,在下载过程中记录每个线程已拷贝数据的数量,如果下载中断,比如无信号断线.电量不足等情况下,这就需要使用到断点续传功能,下次启动时从记录位置继续下载,可避免重复部分的下载.这里采用数据库来记录下载的进度. 效果图:   断点续传 1.断点续传需要在下载过程中记录每条线程的下载进度 2.每次下载开始之前先读取数据库

  • 命令行使用支持断点续传的java多线程下载器

    复制代码 代码如下: package org.load.download; import java.io.File;import java.io.IOException;import java.io.InputStream;import java.io.RandomAccessFile;import java.text.DecimalFormat; import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;impo

  • php实现的css文件背景图片下载器代码

    本文实例讲述了php实现的css文件背景图片下载器代码.分享给大家供大家参考.具体实现方法如下: 下载css文件里面的背景图片是我们这些盗版份子长期搞的事情,下载个css图片下载器常出现各种广告弹窗,实在扛不住.这里就提供了一个php版的css文件背景图片下载器给大家. 把文件放到php程序目录 dos下面 php.exe cssImages.php 0 http://www.xxxx.com/css/style.css \images\ 先在php程序目录建个images文件夹,呵呵,贴代码:

  • 关于WIN32.EXE变态木马下载器的解决办法

    一.WIN32.EXE的来源:http://fdghewrtewrtyrew.biz/adv/130/win32.exe 二.运行后的表现:此WIN32.EXE通过80和8080端口访问若干个IP,若防火墙不能监测到或令防火墙允许该访问,WIN32.EXE会自动下载木马Kernels8.exe到system32目录下:Kernels8.exe自网络下载1.dlb.2.dlb.....等一堆木马到当前用户文件夹中,并自动运行.下载的木马加载运行后,又从网络上下载其它木马/蠕虫. 木马/蠕虫完全下载

  • 替换ctfmon.exe的下载器window.exe的方法

    病毒描述: 此病毒利用替换输入法输入程序的方法伪装自身,从而可以利用原先已有的ctfmon启动项目启动自身,并进行下载木马和感染htm文件等操作 File: window.exe Size: 19380 bytes Modified: 2007年10月19日, 17:42:28 MD5: BDAA1AB926518C7D3C05B730C8B5872C SHA1: BF4C82AA7F169FF37F436B78BBE9AA7FD652118A CRC32: BEC77526 1.病毒运行后,生

  • python使用urllib模块开发的多线程豆瓣小站mp3下载器

    复制代码 代码如下: #! /usr/bin/python2.7# -- coding:utf-8 -- import os, urllib,urllib2, thread,threadingimport re #匹配音乐urlreg=re.compile('{"name":"(.+?)".+?"rawUrl":"(.+?)",.+?}', re.I) class downloader(threading.Thread):  

  • iOS开发实现下载器的基本功能(1)

    今天,做了一个下载器的Demo,即从本地配置的Apache服务器上,下载指定的文件.这次,我们下载服务器根目录下的html.mp4文件. 按照惯例,我们先创建一个URL对象和请求.  NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/html.mp4"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; 这里有两点需要注意,第一,这个url的字符串是全英文的,如

  • 利用stream实现一个简单的http下载器

    其实这个http下载器的功能已经相当完善了,支持:限速.post投递和上传.自定义http header.设置user agent.设置range和超时 而且它还不单纯只能下载http,由于使用了stream,所以也支持其他协议,你也可以用它来进行文件之间的copy.纯tcp下载等等.. 完整demo请参考:https://github.com/waruqi/tbox/wiki stream.c /* ///////////////////////////////////////////////

  • 利用Python制作一个MOOC公开课下载器

    目录 导语 开发工具 环境搭建 先睹为快 原理简介 导语 记得很久以前写过一些中国大学MOOC上的视频下载器,不过好像都已经年久失修了.正好最近有需要,所以重新写了一个,顺便上来分享一波,寒假大家也可以用它来下载点课程内卷一下: 废话不多说,让我们愉快地开始吧~ 开发工具 Python版本:3.7.8 相关模块: DecryptLogin模块: tqdm模块: click模块: argparse模块: 以及一些python自带的模块. 环境搭建 安装Python并添加到环境变量,pip安装需要的

  • C# 利用VS编写一个简单的网游客户端

    目录 一.测试连接服务器 二.设计客户端 三.运行效果 四.总结 一.测试连接服务器 1.打开cmd,输入ping 10.1.230.74 2.输入telnet,进入telnet界面 3.输入set localecho,打开本地回显: 4.连接服务器,输入命令open 10.1.230.74 3900 二.设计客户端 1.新建项目 打开VS2022选择新建Windows窗体应用 如果没找到,说明没有安装相应的配置,可以添加工具 选择 安装成功就能找到了. 2.设计界面 新建完成后,会直接来到Fo

  • 利用jQuery实现一个简单的表格上下翻页效果

    前言 本文主要介绍的是利用jQuery实现一个简单的表格上下翻页效果,注:实现原理与轮播图相似.下面话不多说,来看看详细的 实现方法吧. html: <div class="popup day02-popup04"> <div class="group-caption"> <span>日期</span><span>参与团购场次</span><span class="result&

  • 利用c++写一个简单的推箱子小游戏

    效果图 相信各位都肯定完整这种推箱子的小游戏.游戏玩法很简单,那就是一个人把所有的箱子推动到对应的位置那就可以赢了. 那么我们接下来看看这个推箱子的游戏改怎么写 char map[10][10]= { {'#','#','#','#','#','#','#','#','#','#'}, {'#','#','#','#',' ',' ','!',' ',' ','#'}, {'#',' ',' ',' ',' ','o',' ',' ',' ','#'}, {'#',' ',' ',' ',' '

  • 利用JavaScript写一个简单计算器

    效果如下: 参考程序: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=d

  • 利用Python制作一个简单的天气播报系统

    目录 前言 工具 天气数据来源 代码实现 总结 前言 大家好,我是辣条 相信大家都能感觉到最近天气的多变,好几次出门半路天气转变.辣条也深受其扰,直接给我整感冒,就差被隔离起来了,既然天气我没法做主,那不如用python整个天气爬虫来获取天气情况.这样也好可以进行一个提前预防 工具 python3.7 pycharm pyttsx3:语音播报库 天气数据来源 找寻一个天气网站 比如说我们要查询某地的天气,在输入地名后就能看到结果. 我们可以看到网站的url会有变化: 每个城市的天气信息url就是

  • 如何利用PyQt5制作一个简单的登录界面

    目录 环境配置 额外工具配置 生成UI界面 总结 环境配置 新建python虚拟环境并激活 conda create -n pyqt python=3.8 conda activate py36 安装pyqt5 pip install pyqt5 安装pyqt5-tools pip install pyqt5-tools 在PyCharm中新建一个qtdemo工程,并使用这个新建的python虚拟环境作为工程环境 额外工具配置 依次点击File---Settings---Tools---Exte

  • 利用Python实现一个简单的Web汇率计算器

    目录 Dash是什么 网页搭建步骤 安装相关依赖(库) 导入相关包 构建app 构建结果输出函数 网页结构Layout搭建 callback回调参数设定 界面效果 前段时间刚接触到前端网页开发,但是对于刚入门的小白而言,像flask.Django等这类稍大型的框架确实不太适合,今天这个Dash是集众家之长于一体的轻量化Web开发库. Dash是什么 Dash 是一个用于构建基于 Web 的应用程序的 Python 库,无需 JavaScript . Dash 同时也是用于创建分析 Web 应用程

  • 利用Rust实现一个简单的Ping应用

    目录 目标 命令行解析 实现Ping 周期性发送 其他 验证 总结 这两年Rust火的一塌糊涂,甚至都烧到了前端,再不学习怕是要落伍了.最近翻了翻文档,写了个简单的Ping应用练练手,被所有权折腾的够呛,相比起Golang上手难度大很多,现将开发中的一些问题总结如下,所有源码见ring. 目标 实现一个Ping,功能包含: 命令行解析 实现ICMP协议,pnet包中已经包含了ICMP包定义,可以使用socket2库发送 周期性发送Ping,通过多线程发送,再汇总结果 监听退出信号 命令行解析 系

随机推荐