1.最好会使用一种跨平台线程池库(C/C++),网站组可使用系统自带的库,来开发一个命令行网络程序,下载文件
iston-video-converter.exe
2.至少可以显示已下载的字节数。
3.设置线程池最大线程数为5。
4.使用线程池开启10个下载任务,正在现在的线程需打印(进度(即字节数),线程ID)
//opra_curl.cpp
iston-video-converter.exe
2.至少可以显示已下载的字节数。
3.设置线程池最大线程数为5。
4.使用线程池开启10个下载任务,正在现在的线程需打印(进度(即字节数),线程ID)
5.验证等待中的线程继续时是否是从线程池获取已创建好的线程,即对比线程ID.
makefile
#
# There exist several targets which are by default empty and which can be
# used for execution of your targets. These targets are usually executed
# before and after some main targets. They are:
#
# .build-pre: called before 'build' target
# .build-post: called after 'build' target
# .clean-pre: called before 'clean' target
# .clean-post: called after 'clean' target
# .clobber-pre: called before 'clobber' target
# .clobber-post: called after 'clobber' target
# .all-pre: called before 'all' target
# .all-post: called after 'all' target
# .help-pre: called before 'help' target
# .help-post: called after 'help' target
#
# Targets beginning with '.' are not intended to be called on their own.
#
# Main targets can be executed directly, and they are:
#
# build build a specific configuration
# clean remove built files from a configuration
# clobber remove all built files
# all build all configurations
# help print help mesage
#
# Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and
# .help-impl are implemented in nbproject/makefile-impl.mk.
#
# Available make variables:
#
# CND_BASEDIR base directory for relative paths
# CND_DISTDIR default top distribution directory (build artifacts)
# CND_BUILDDIR default top build directory (object files, ...)
# CONF name of current configuration
# CND_PLATFORM_${CONF} platform name (current configuration)
# CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration)
# CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration)
# CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration)
# CND_PACKAGE_DIR_${CONF} directory of package (current configuration)
# CND_PACKAGE_NAME_${CONF} name of package (current configuration)
# CND_PACKAGE_PATH_${CONF} path to package (current configuration)
#
# NOCDDL
# Environment
MKDIR=mkdir -p
CP=cp -u
CCADMIN=CCadmin
ANT=ant
MAIN_VERSION=1.0.x
LIB_VERSION=1.0.0
# build
build: .build-init .build-post
.build-pre:
# Add your pre 'build' code here...
.build-init:
${MKDIR} dist
.build-post: .build-app-dir .build-app-resources .build-app-dll .build-impl
# Add your post 'build' code here...
${CP} E:/software/MinGW/bin/libgcc_s_dw2-1.dll dist/${CONF}/MinGW-Windows/
# ${CP} ../../dist/${CONF}/MinGW-Windows/*.dll dist/${CONF}/MinGW-Windows/
${CP} E:/software/project/tool/1.0.x/win32/share/Release/QX_Tool.1.0.0.dll dist/${CONF}/MinGW-Windows/
${CP} resources/*.txt dist/${CONF}/MinGW-Windows/
# ${CP} E:/software/Lib/communications/curl-7.28.1/win32/release/share/libcurl-4.dll dist/${CONF}/MinGW-Windows/
${CP} E:/software/Lib/common/boost-1.46.1/win32/release/share/mt/libboost_regex-mgw44-mt-1_46_1.dll dist/${CONF}/MinGW-Windows/
${CP} E:/software/Lib/common/boost-1.46.1/win32/release/share/mt/libboost_thread-mgw44-mt-1_46_1.dll dist/${CONF}/MinGW-Windows/
${CP} E:/software/project/tool/win32/share/Release/QX_Tool.dll dist/${CONF}/MinGW-Windows/
# ${CP} E:/software/Lib/i18n/iconv-1.14/win32/release/share/libiconv-2.dll dist/${CONF}/MinGW-Windows/
${CP} E:/software/Lib/communications/curl-7.28.1/win32/release/share/libcurl-4.dll dist/${CONF}/MinGW-Windows/
.build-app-dir:
.build-app-resources:
.build-app-dll:
# clean
clean: .clean-post
.clean-pre:
# Add your pre 'clean' code here...
.clean-post: .clean-impl
# Add your post 'clean' code here...
# clobber
clobber: .clobber-post
.clobber-pre:
# Add your pre 'clobber' code here...
.clobber-post: .clobber-impl
# Add your post 'clobber' code here...
# all
all: .all-post
.all-pre:
# Add your pre 'all' code here...
.all-post: .all-impl
# Add your post 'all' code here...
# build tests
build-tests: .build-tests-post
.build-tests-pre:
# Add your pre 'build-tests' code here...
.build-tests-post: .build-tests-impl
# Add your post 'build-tests' code here...
# run tests
test: .test-post
.test-pre:
# Add your pre 'test' code here...
.test-post: .test-impl
# Add your post 'test' code here...
# help
help: .help-post
.help-pre:
# Add your pre 'help' code here...
.help-post: .help-impl
# Add your post 'help' code here...
# include project implementation makefile
include nbproject/Makefile-impl.mk
# include project make variables
include nbproject/Makefile-variables.mk
#PROJECT-CONFIG
CND_DISTDIR=dist
.PHONY: .build-init
Makefile-Debug.mk
#
# Generated Makefile - do not edit!
#
# Edit the Makefile in the project folder instead (../Makefile). Each target
# has a -pre and a -post target defined where you can add customized code.
#
# This makefile implements configuration specific macros and targets.
# Environment
MKDIR=mkdir
CP=cp
GREP=grep
NM=nm
CCADMIN=CCadmin
RANLIB=ranlib
CC=gcc.exe
CCC=g++.exe
CXX=g++.exe
FC=gfortran.exe
AS=as.exe
# Macros
CND_PLATFORM=MinGW-Windows
CND_CONF=Debug
CND_DISTDIR=dist
# Include project Makefile
include Makefile
# Object Directory
OBJECTDIR=build/${CND_CONF}/${CND_PLATFORM}
# Object Files
OBJECTFILES= \
${OBJECTDIR}/src/main.o \
${OBJECTDIR}/src/test_thread_pool.o \
${OBJECTDIR}/src/boost_thread_pool.o \
${OBJECTDIR}/src/opra_curl.o
# C Compiler Flags
CFLAGS=
# CC Compiler Flags
CPPFLAGS=
CXXFLAGS=-g -Wall -MMD -MP -MF $@.d -m32 -D_UNICODE -D__QXWIN32__ \
-I/E/software/project/tool/1.0.x/include \
-I/E/software/Lib/tests/gtest-1.5.0/win32/release/static/include-compile \
-I/E/software/Lib/tests/gtest-1.5.0/win32/release/static/include \
-Iinclude \
-I/E/software/Lib/common/boost-1.46.1/include \
-Iinclude/boost \
-I/E/software/Lib/communications/curl-7.28.1/include
# Fortran Compiler Flags
FFLAGS=
# Assembler Flags
ASFLAGS=
LDLIBSOPTIONS=-L/E/software/Lib/tests/gtest-1.5.0/win32/release/static -L/E/software/project/tool/1.0.x/win32/share/Release -lgtest -lQX_Tool.1.0.0 -L/E/software/Lib/common/boost-1.46.1/win32/release/share/mt -lboost_thread-mgw44-mt-1_46_1 -L/E/software/Lib/communications/curl-7.28.1/win32/release/share -lcurl-4
# Build Targets
.build-conf: ${BUILD_SUBPROJECTS}
"${MAKE}" -f nbproject/Makefile-Debug.mk dist/Debug/MinGW-Windows/threadpool.exe
dist/Debug/MinGW-Windows/threadpool.exe: ${OBJECTFILES}
${MKDIR} -p dist/Debug/MinGW-Windows
${LINK.cc} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/threadpool.exe ${OBJECTFILES} ${LDLIBSOPTIONS}
${OBJECTDIR}/src/main.o: nbproject/Makefile-${CND_CONF}.mk src/main.cpp
${MKDIR} -p ${OBJECTDIR}/src
${RM} $@.d
$(COMPILE.cc) -o ${OBJECTDIR}/src/main.o src/main.cpp
${OBJECTDIR}/src/test_thread_pool.o: nbproject/Makefile-${CND_CONF}.mk src/test_thread_pool.cpp
${MKDIR} -p ${OBJECTDIR}/src
${RM} $@.d
$(COMPILE.cc) -o ${OBJECTDIR}/src/test_thread_pool.o src/test_thread_pool.cpp
${OBJECTDIR}/src/boost_thread_pool.o: nbproject/Makefile-${CND_CONF}.mk src/boost_thread_pool.cpp
${MKDIR} -p ${OBJECTDIR}/src
${RM} $@.d
$(COMPILE.cc) -o ${OBJECTDIR}/src/boost_thread_pool.o src/boost_thread_pool.cpp
${OBJECTDIR}/src/opra_curl.o: nbproject/Makefile-${CND_CONF}.mk src/opra_curl.cpp
${MKDIR} -p ${OBJECTDIR}/src
${RM} $@.d
$(COMPILE.cc) -o ${OBJECTDIR}/src/opra_curl.o src/opra_curl.cpp
# Subprojects
.build-subprojects:
# Clean Targets
.clean-conf: ${CLEAN_SUBPROJECTS}
${RM} -r build/Debug
${RM} dist/Debug/MinGW-Windows/threadpool.exe
# Subprojects
.clean-subprojects:
# Enable dependency checking
.dep.inc: .depcheck-impl
include .dep.inc
//opra_curl.h
/*
* opra_curl.h
*
* Created on: 2013-3-14
* Author: hp
*/
#ifndef OPRA_CURL_H_
#define OPRA_CURL_H_
#include <stdlib.h>
#include <cstdio>
#include <stdio.h>
#include <vector>
#include <list>
#include <string.h>
#include <iostream>
#include <fstream>
#include <curl/curl.h>
#include <curl/easy.h>
//#include "VideoDownload/videodownload_info.h"
using namespace std;
typedef int (*VDownGetPercentage)(void* user_data, double icomplete, double itotal,
int cur_file_index);
//暂时只用curl_proxy_http_type下载
enum CurlProxyType
{
curl_proxy_null,
curl_proxy_http_type, /* added in 7.10, new in 7.19.4 default is to use
CONNECT HTTP/1.1 */
curl_proxy_http_1_0,/* added in 7.19.4, force to use CONNECT
HTTP/1.0 */
curl_proxy_socks4,/* support added in 7.15.2, enum existed already
in 7.10 */
curl_proxy_socks5,/* added in 7.10 */
curl_proxy_socks4a,/* added in 7.18.0 */
curl_proxy_socks5_hostname/* Use the SOCKS5 protocol but pass along the*/
};
typedef struct ProxyData ProxyData;
struct ProxyData
{
CurlProxyType proxy_type;
char* proxy_addr;
char* proxy_port;
char* proxy_user;
char* proxy_password;
};
struct MyBar
{
VDownGetPercentage proc;
CURL* handle;
double lase_file_size;
void* user_data;
};
int ConvertUint64ToChar(char* file_length, uint64_t file_size);
//暂停函数
int PauseDownload(CURL* handle);
//恢复下载函数
int ResumeDownload(CURL* handle);
//停止函数
int StopDownload(CURL* handle);
//下载到文件进度条回调函数
int MyProgressFunc(void *Bar, double t, /* dltotal */
double d, /* dlnow */
double ultotal, double ulnow);
//下载到内存进度条回调函数
int UrlProgressFunc(void *Bar, double t, /* dltotal */
double d, /* dlnow */
double ultotal, double ulnow);
//写到内存 的写函数
size_t Writer(void *data, size_t size, size_t nmemb, void* writerData);
class OpraCurl
{
public:
//设置代理
int SetCurlProxy(CURL* conn, ProxyData* proxy_data);
//写到内存
int DownloadHtml(char* url, string* p_buffer, ProxyData* proxy_data, int timeout,
void* user_data, VDownGetPercentage GetPercentage);
//下载到文件
int DownloadVideo(void* self, const char* video_url,
const char* target_file_path, int keep_down, ProxyData* proxy_data,
void* user_data, VDownGetPercentage GetPercentage);
OpraCurl();
~OpraCurl();
};
#endif /* OPRA_CURL_H_ */
//opra_curl.cpp
/*
* opra_curl.cpp
*
* Created on: 2013-3-14
* Author: hp
*/
#include "opra_curl.h"
#include "tool/file/file_access.h"
//#include "common/common.h"
//#include "VideoDownload/videodownload_error.h"
int ConvertUint64ToChar(char* file_length, uint64_t file_size)
{
#if defined(_UNICODE) || defined(UNICODE)
sprintf(file_length, "%I64u-", file_size);
#else
sprintf(file_length, "%llu-", file_size);
#endif
return 0;
}
int PauseDownload(CURL* handle)
{
curl_easy_pause(handle, CURLPAUSE_RECV);
return 0;
}
int ResumeDownload(CURL* handle)
{
curl_easy_pause(handle, CURLPAUSE_RECV_CONT);
return 0;
}
int StopDownload(CURL* handle)
{
return -1;
}
int MyProgressFunc(void *Bar, double t, /* dltotal */
double d, /* dlnow */
double ultotal, double ulnow)
{
if ((int) (d * 100.0 / t) >= 0)
{
MyBar* my_bar = (MyBar*) Bar;
VDownGetPercentage proc = (VDownGetPercentage) my_bar->proc;
int ret = proc(my_bar->user_data, (d + my_bar->lase_file_size),
(t + my_bar->lase_file_size), 0);
if (-2 == ret)
{
return PauseDownload(my_bar->handle);
}
else if (1 == ret)
{
return ResumeDownload(my_bar->handle);
}
else if (-1 == ret)
{
return StopDownload(my_bar->handle);
}
}
return 0;
}
int UrlProgressFunc(void *Bar, double t, /* dltotal */
double d, /* dlnow */
double ultotal, double ulnow)
{
// if ((int) (d * 100.0 / t) >= 0)
// {
MyBar* my_bar = (MyBar*) Bar;
VDownGetPercentage proc = (VDownGetPercentage) my_bar->proc;
int ret = proc(my_bar->user_data, (d + my_bar->lase_file_size),
(t + my_bar->lase_file_size), 0);
if (-2 == ret)
{
return PauseDownload(my_bar->handle);
}
else if (1 == ret)
{
return ResumeDownload(my_bar->handle);
}
else if (-1 == ret)
{
return StopDownload(my_bar->handle);
}
// }
return 0;
}
//写到内存
size_t Writer(void *data, size_t size, size_t nmemb, void* writerData)
{
unsigned long sizes = size * nmemb;
string* str_data = (string*) writerData;
str_data->append((char*) data, sizes);
return sizes;
}
//设置代理
int OpraCurl::SetCurlProxy(CURL* conn, ProxyData* proxy_data)
{
if (!proxy_data)
{
return -1;
}
if (proxy_data->proxy_addr && strlen(proxy_data->proxy_addr) > 0
&& proxy_data->proxy_port && strlen(proxy_data->proxy_port) > 0)
{
string curl_addr_port = string(proxy_data->proxy_addr) + ":"
+ string(proxy_data->proxy_port);
curl_easy_setopt(conn, CURLOPT_PROXY, curl_addr_port.c_str());
string curl_user_password;
if (proxy_data->proxy_user && proxy_data->proxy_password)
{
curl_user_password = string(proxy_data->proxy_user) + ":"
+ string(proxy_data->proxy_password);
curl_easy_setopt(conn, CURLOPT_PROXYUSERPWD,
curl_user_password.c_str());
}
switch (proxy_data->proxy_type)
{
case curl_proxy_http_type:
curl_easy_setopt(conn, CURLOPT_HTTPPROXYTUNNEL, 1L);
curl_easy_setopt(conn, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
break;
case curl_proxy_http_1_0:
curl_easy_setopt(conn, CURLOPT_PROXYTYPE, CURLPROXY_HTTP_1_0);
break;
case curl_proxy_socks4:
curl_easy_setopt(conn, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
break;
case curl_proxy_socks5:
curl_easy_setopt(conn, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
break;
case curl_proxy_socks4a:
curl_easy_setopt(conn, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4A);
break;
case curl_proxy_socks5_hostname:
curl_easy_setopt(conn, CURLOPT_PROXYTYPE,
CURLPROXY_SOCKS5_HOSTNAME);
break;
default:
break;
}
return 0;
}
return -1;
}
int OpraCurl::DownloadHtml(char* url, string* p_buffer, ProxyData* proxy_data,
int timeout, void* user_data, VDownGetPercentage GetPercentage)
{
CURL* curl = curl_easy_init();
MyBar* bar = (MyBar*) malloc(sizeof( MyBar));
memset(bar, 0, sizeof(MyBar));
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, url);
SetCurlProxy(curl, proxy_data);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "test-agent/1.0");
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Writer);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)p_buffer);
if (GetPercentage)
{
bar->handle = curl;
bar->proc = GetPercentage;
bar->lase_file_size = 0;
bar->user_data = user_data;
// Install the callback function
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, bar);
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, UrlProgressFunc);
}
curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
free(bar);
return 0;
}
int OpraCurl::DownloadVideo(void* self, const char* video_url,
const char* target_file_path, int keep_down, ProxyData* proxy_data,
void* user_data, VDownGetPercentage GetPercentage)
{
int file_exist = QXIsFileExists(target_file_path);
uint64_t file_size = 0;
if (file_exist)
{
if (keep_down == 1)
{
file_size = QXGetFileSize(target_file_path);
}
else
{
::remove(target_file_path);
}
}
FILE *file = QXfopen(target_file_path, "ab+");
if (!file)
{
return -1;
}
// set up curl
CURL* easyhandle = curl_easy_init();
curl_easy_setopt( easyhandle, CURLOPT_URL, video_url);
MyBar* bar = (MyBar*) malloc(sizeof( MyBar));
memset(bar, 0, sizeof(MyBar));
if (GetPercentage)
{
bar->handle = easyhandle;
bar->proc = GetPercentage;
bar->lase_file_size = file_size;
bar->user_data = user_data;
// Install the callback function
curl_easy_setopt(easyhandle, CURLOPT_NOPROGRESS, 0);
curl_easy_setopt(easyhandle, CURLOPT_PROGRESSDATA, bar);
curl_easy_setopt(easyhandle, CURLOPT_PROGRESSFUNCTION, MyProgressFunc);
}
if (file_exist && keep_down == 1)
{
//curl_easy_setopt(easyhandle, CURLOPT_RESUME_FROM_LARGE, file_size);
char num[70] =
{ 0 };
memset(num, 0, 70);
ConvertUint64ToChar(num, file_size);
string range = num;
curl_easy_setopt(easyhandle, CURLOPT_RANGE, range.c_str());
}
if (proxy_data)
{
SetCurlProxy(easyhandle, proxy_data);
}
curl_easy_setopt(easyhandle, CURLOPT_VERBOSE, 1L);
curl_easy_setopt( easyhandle, CURLOPT_WRITEDATA, file);
curl_easy_setopt(easyhandle, CURLOPT_FOLLOWLOCATION, 1);
//1.注意,这里有返回值没处理.
curl_easy_perform(easyhandle);
fclose(file); //make sure to close file
curl_easy_cleanup(easyhandle);
free(bar);
return 0;
}
OpraCurl::OpraCurl()
{
}
OpraCurl::~OpraCurl()
{
}
main.cpp
#include "boost_thread_pool.h"
#include <windows.h>
#include <boost/threadpool.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/smart_ptr.hpp>
#include <iostream>
#include <sstream>
#include <algorithm>
#include "threadpool.hpp"
#include "opra_curl.h"
using namespace std;
using namespace boost::threadpool;
boost::mutex m_io_monitor;
string g_diff;
int PrintfProcessForMulThread(void* user_data, double complete_num, double total_num,
int cur_file_index)
{
cout << "complete:" << complete_num << "B\ttotal:" << total_num
<< "B\tcur_file_index:" << boost::this_thread::get_id() << endl;
return 0;
}
class MyTest
{
public:
MyTest(){m_index = 0; m_max = 3;}
~MyTest(){}
void Run()
{
for(; m_index < m_max ; m_index++)
{
Sleep(3000);
cout<<boost::this_thread::get_id()<<m_index<<endl;
}
}
private:
int m_index;
int m_max;
};
void Run2(string str)
{
//char ch = char(rand());
g_diff.append("1");
ProxyData* proxy_data = (ProxyData*)calloc(1, sizeof(ProxyData));
proxy_data->proxy_type = curl_proxy_http_type;
proxy_data->proxy_addr = "192.168.0.1";
proxy_data->proxy_port = "808";
OpraCurl down;
down.DownloadVideo(NULL, "www.istonsoft.com/downloads/iston-video-converter.exe",
str.append(g_diff).append(".exe").c_str(), 1, proxy_data, NULL, PrintfProcessForMulThread);
free(proxy_data);
}
int main (int argc, char * const argv[])
{
string dir = "C:\\ll\\";//QXGetRunDirectory(argv[0]);
pool tp;
tp.size_controller().resize(5);
int step = 1;
for(; step <= 10; step++)
{
// boost::shared_ptr<MyTest > job(new MyTest());
// //tp->schedule(prio_task_func(5, boost::bind(&merge_job<image>::run, job)));
// schedule(tp, boost::bind(&MyTest::Run, job));
// // schedule(tp, job);
schedule(tp, boost::bind(&Run2, dir));
}
tp.wait(); // wait until all partitions are sorted
return 0;
}