准备写一个http下载,支持断点下载,多线程下载
来源:互联网 发布:阿里云虚拟主机 使用 编辑:程序博客网 时间:2024/04/30 19:22
实现这个功能,需要使用http中分块下载,先写个小程序试试http中使用Range:bytes功能
#include <iostream>#include <iosfwd>#include <fstream>#include <regex>#include <string>#include <winsock2.h>#include <pthread.h>#include <map>#include <queue>/***实现多线程http协议下载文件的功能,支持断点续传和多线程同时下载*http请求使用Range: bytes完成*为了保证文件的完整性,有两种方式*1,使用生产者/消费者模式,将读取的信息放入队列中,由队列写文件*2,同时写n个临时文件,最后执行完成拼接在一起***/using namespace std;SOCKET sock;//测试主机和端口const char *testHostName="ww3.sinaimg.cn";const short testPort=80;const string testPortChar="80";//文件地址const char *url="/mw690/60d02b59tw1ehspkw5ewfg20dm05wb1p.gif";//分块下载的块大小const int getSize=10000;int fileNameInt;//发送http请求包bool sendHttpQuery(string sendQueryStr){ int n=0; //初始化socket sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { cout << "建立socket失败! 错误码: " << WSAGetLastError() << endl; return false; } sockaddr_in sa = { AF_INET }; n = bind(sock, (sockaddr*)&sa, sizeof(sa)); if (n == SOCKET_ERROR) { cout << "bind函数失败! 错误码: " << WSAGetLastError() << endl; return false; } struct hostent *p = gethostbyname(testHostName); if (p == NULL) { cout << "主机无法解析出ip! 错误吗: " << WSAGetLastError() << endl; return false; } sa.sin_port = htons(testPort); memcpy(&sa.sin_addr, p->h_addr, 4);// with some problems ??? //sa.sin_addr.S_un.S_addr = inet_addr(*(p->h_addr_list)); //cout << *(p->h_addr_list) << endl; //连接 n = connect(sock, (sockaddr*)&sa, sizeof(sa)); if (n == SOCKET_ERROR) { cout << "connect函数失败! 错误码: " << WSAGetLastError() << endl; return false; } //string reqInfo = "GET / HTTP/1.1\r\n Host:www.baidu.com \r\n Connection:Keep-Alive\r\n\r\n "; //string reqInfo ="GET http://c.csdnimg.cn/rabbit/notev2/js/notify.js HTTP/1.1 \r\n Host: c.csdnimg.cn \r\n Connection: keep-alive \r\n Accept: */* \r\n User-Agent: Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36 \r\n Referer: http://www.csdn.net/ \r\n Accept-Encoding: gzip, deflate, sdch \r\n Accept-Language: zh-CN,zh;q=0.8\r\n\r\n"; //string reqInfo = "GET /huajiao/huajiao.html HTTP/1.1 \r\n Host: se.360.cn \r\n Connection: close \r\n Accept-Encoding: gzip, deflate, sdch \r\n Accept-Language: zh-CN,zh;q=0.8 \r\n Cookie: __huid=106HCYajdj5TzIlJ9HVN0evB27Lr1Z8JneHl8nAKepKUc%3D; __guid=132730903.2645167981534180400.1426119249932.2551; _ga=GA1.2.1411504458.1447744075; guid=54771369.514003739225082050.1466048704517.24 \r\n\r\n"; //string reqInfo = "GET /thread-551469-1.html HTTP/1.1\r\nHost:bbs.51cto.com:80\r\nConnection:Close\r\n\r\n"; //按照http送GET请求 cout<<"发送http请求:"+sendQueryStr<<endl; if (SOCKET_ERROR == send(sock, sendQueryStr.c_str(), sendQueryStr.size(), 0)) { cout << "send error! 错误码: " << WSAGetLastError() << endl; closesocket(sock); return false; } return true;}//从http的返回头信息中解析出文件长度char * getResponseLeng(const char receiveBuf[1024]){ //找到Content-Range: bytes 0-1/之后的字符串lengStartChar char *lengStartChar = strstr(receiveBuf, "Content-Range: bytes 0-1/"); int tmpSize=sizeof("Content-Range: bytes 0-1/");//注意sizeof长度将结束符计算进去,后面需要减掉1 //char *tmpSizeChar; //sprintf(tmpSizeChar,"%d",tmpSize); //cout<<(string)tmpSizeChar<<endl; //char *lengEndchar=strstr(buf, "\r\n"); int i=0; bool isEnd=false; //在lengStartChar找到\r\n之前的位置 while(!isEnd){ if(lengStartChar[i+1]!='\r')i++; else{ if(lengStartChar[i+2]=='\n')isEnd=true; else i++; } } //将lengStartChar中关于长度的一段赋值给长度字符串,注意减去结束符 char *leng=new char(10); memset(leng,0x00,10); memcpy(leng,lengStartChar+tmpSize-1,i-tmpSize+2); //cout<<"111 "+(string)leng+" 111"<<endl; return leng;}int main(){ int n; char buf[1024]; memset(buf, 0, sizeof(buf)); fstream file; WORD version(0); WSADATA wsadata; int socket_return(0); version = MAKEWORD(2,0); socket_return = WSAStartup(version,&wsadata); if (socket_return != 0) { return 0; } file.open("D:\\testmap\\test.gif" ,ios::out|ios::binary); cout << " 文档打开 D:\\testmap\\test.gif" << endl; if(!file.is_open()){ cout << " 文档打开失败! D:\\testmap\\test.gif" << endl; } //for() string strFirst="GET "+(string)url+" HTTP/1.1\r\nHost:"+(string)testHostName+":"+testPortChar+"\r\nRange:bytes=0-1\r\nConnection:Close\r\n\r\n"; //发送http请求 if(!sendHttpQuery(strFirst)){ cout<<" http 请求发送失败! "<<endl; return 0; } //思路:将Content-Range: bytes 0-1/后面的值作为长度解析出来 //再根据文件长度决定循环几次请求(后续实现分配几个线程下载) n = recv(sock, buf, sizeof(buf)-1, 0); cout<<buf<<endl; char *lengChar=getResponseLeng(buf); cout<<"长度为 :"+(string)lengChar<<endl; int lengInt=atoi(lengChar); //得到每次取1000长度总共需要循环的次数 int getTimeInt=lengInt/getSize; int i=0; while(i<=getTimeInt){ char tmpBuf[1024]; memset(tmpBuf, 0, sizeof(tmpBuf)); char *startMark=new char(10); char *endMark=new char(10);//设置开始地址,结束地址,注意 memset(startMark,0,10); memset(endMark,0,10); //string startMark; //string endMark; // startMark=itoa(); sprintf(startMark,"%d",(i*getSize+0)); sprintf(endMark,"%d",(i*getSize+(getSize-1))); //startMark[5]='\0'; //endMark[5]='\0'; string strFirst="GET "+(string)url+" HTTP/1.1\r\nHost:"+(string)testHostName+":"+testPortChar+"\r\nRange:bytes="+(string)startMark+"-"+(string)endMark+"\r\nConnection:Close\r\n\r\n"; //发送http请求 if(!sendHttpQuery(strFirst)){ cout<<" http 请求发送失败! "<<endl; return 0; } n = recv(sock, tmpBuf, sizeof(tmpBuf)-1, 0); char *cpos = strstr(tmpBuf, "\r\n\r\n"); //显示响应头 //char *requestHeader=new char(200); //memset(requestHeader,0,200); //memcpy(requestHeader,tmpBuf,cpos - tmpBuf+1); file.write(cpos + strlen("\r\n\r\n"), n - (cpos - tmpBuf) - strlen("\r\n\r\n")); // cout<<cpos + strlen("\r\n\r\n") <<endl; //cout<<requestHeader<<endl; while ((n = recv(sock, tmpBuf, sizeof(tmpBuf)-1, 0)) > 0) { file.write(tmpBuf, n); } i++; } file.close(); return 0;}
0 0
- 准备写一个http下载,支持断点下载,多线程下载
- 多线程下载断点下载
- 多线程下载,断点下载
- Android -- 多线程下载, 断点下载
- Android断点下载,多线程下载
- java实现http多线程下载,断点回复
- JavaSE-Http断点/多线程下载文件
- 服务器端支持 断点下载
- java 多线程断点下载
- 网络多线程断点下载
- 网络多线程断点下载
- 网络多线程断点下载
- android多线程断点下载
- 多线程断点下载原理
- 多线程断点下载文件
- java 多线程断点下载
- android 多线程断点下载
- android多线程断点下载
- XML文件的常见解析方法
- hd 2089 不要62
- 文章标题
- Maven 手动添加 JAR 包到本地仓库
- lintcode flatten-binary-tree-to-linked-list 将二叉树拆成链表 前序扁平化 中序扁平化
- 准备写一个http下载,支持断点下载,多线程下载
- 源码-PL/SQL从入门到精通-第十章-使用游标-Part 2
- 无主之地1
- (转译)Objective-C的动态特性 runtime
- jzoj 1386. 【2012.02.18普及组】郁闷的记者——拓扑排序
- android中的HandlerThread类 Runtime.getRuntime()报错null environmentAndroid执行shell命令Android获取系统剩余可用内存信息
- tjut 5384
- UITabBarController
- JSTL