linux c++下载http文件并显示进度<转>
2014-09-01 11:26
489 查看
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdlib.h> #include <iostream> #include <string.h> #include <unistd.h> #include <fstream> #include <vector> #include <pthread.h> using namespace std; typedef string::size_type (string::*find_t)(const string& delim, string::size_type offset) const; vector<string> Split(const string& s, const string& match, bool removeEmpty=false, bool fullMatch=false) { vector<string> result; // return container for tokens string::size_type start = 0, // starting position for searches skip = 1; // positions to skip after a match find_t pfind = &string::find_first_of; // search algorithm for matches if (fullMatch) { skip = match.length(); pfind = &string::find; } while (start != string::npos) { string::size_type end = (s.*pfind)(match, start); if (skip == 0) end = string::npos; string token = s.substr(start, end - start); if (!(removeEmpty && token.empty())) { result.push_back(token); } if ((start = end) != string::npos) start += skip; } return result; } void SplitProperty(vector<string> property,string* name,string *value) { vector<string>::iterator it=property.begin(); if(it!= property.end()) { name->clear(); name->append(*it); } it++; if(it!= property.end()) { value->clear(); value->append(*it); } } int GetFileSize(char* host,char* file,string* error,int& headersize) { int size=-1; struct sockaddr_in servaddr; struct hostent *hp; string splitline="\r\n"; string PName; string PValue; string splittagbalue=":"; string info; vector<string> properties; vector<string> property; int sock_id; char message[1024*1024] = {0}; int msglen; string request; request.append("HEAD "); request.append(file); request.append(" HTTP/1.1\n"); request.append("Host:"); request.append(host); request.append("\r\n\r\n"); //Get a socket if((sock_id = socket(AF_INET, SOCK_STREAM, 0)) == -1) { error->append("Couldn't get a socket!"); return size; } //book uses bzero which my man pages say is deprecated //the man page said to use memset instead. :-) memset(&servaddr,0,sizeof(servaddr)); //get address for google.com if((hp = gethostbyname(host)) == NULL) { error->append("Couldn't access network."); error->append(host); return size; } //bcopy is deprecated also, using memcpy instead memcpy((char *)&servaddr.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length); //fill int port number and type servaddr.sin_port = htons(80); servaddr.sin_family = AF_INET; //make the connection if(connect(sock_id, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0) { error->append("Couldn't connect!"); return size; } write(sock_id,request.c_str(),request.length()); //read the response msglen = read(sock_id,message,1024*1024); headersize= msglen; info.append(message,0,msglen); close(sock_id); properties =Split(info,splitline,true); vector<string>::iterator it; for (it=properties.begin(); it<properties.end(); it++) { property= Split(*it,splittagbalue,true); SplitProperty(property,&PName,&PValue); if(PName=="Content-Length") { size =atoi(PValue.c_str()); break; } } if(size==-1) { error->append("Resource Not Found!"); } return size; } void DownloadFile(char* host,char* file,char * savefile,float size,int& progress,int hsize) { struct sockaddr_in servaddr; struct hostent *hp; string info; int sock_id; char message[18000] = {0}; char messagetop[18000]={0}; int msglen; float readcount=0; string request; request.append("GET "); request.append(file); request.append(" HTTP/1.1\n"); request.append("Host:"); request.append(host); request.append("\r\n\r\n"); //Get a socket if((sock_id = socket(AF_INET, SOCK_STREAM, 0)) == -1) { return; } //book uses bzero which my man pages say is deprecated //the man page said to use memset instead. :-) memset(&servaddr,0,sizeof(servaddr)); //get address for google.com if((hp = gethostbyname(host)) == NULL) { return; } //bcopy is deprecated also, using memcpy instead memcpy((char *)&servaddr.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length); //fill int port number and type servaddr.sin_port = htons(80); servaddr.sin_family = AF_INET; //make the connection if(connect(sock_id, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0) { return; } //NOW THE HTTP PART!!! //send the request write(sock_id,request.c_str(),request.length()); ofstream outfile (savefile,ofstream::binary); do{ msglen = read(sock_id,message,18000); if(msglen==0) break; if(readcount==0) { int tempindex=0; for(int i =hsize-1;i<msglen;i++) { messagetop[tempindex]= message[i]; tempindex=tempindex+1; } outfile.write (messagetop,tempindex); } else { outfile.write (message,msglen); } readcount=readcount+msglen; progress=readcount/size*100; }while(readcount<=(size+ hsize)); outfile.close(); close(sock_id); //read the response } float filesize; int loadprogress=0; int hsize; pthread_t tUpdateWork; void* UpdateWorCoping(void* data) { DownloadFile("192.168.2.128","/games.data","/usr/games.data",filesize,loadprogress,hsize); } int main(int argc, char** argv) { string error; filesize = GetFileSize("192.168.2.128","/games.data",&error,hsize); pthread_create(&tUpdateWork,NULL,UpdateWorCoping,0); while(loadprogress<99) { printf("Progress %d \n", loadprogress); usleep(1000000); } return 0; }
在使用该代码测试的时候可能会出现的问题:
1.
在DownloadFile 内的有两处:
2.
在DownloadFile() 内的写文件中:
里面有个for循环:for(int i = hsize -1; i<msglen ; i++)
我在亲自测试的发现 hsize - 1 会使文件保存大小跟原始文件有出入。于是暂时改成了 for(int i = hsize ; i<msglen ; i++)
不知道对于其他类型文件是否应该 做 -1 操作。待以后再测一测看看。
相关文章推荐
- linux c++下载http文件并显示进度<转>
- iOS开发之网络编程--4、NSURLSessionDataTask实现文件下载(离线断点续传下载) <进度值显示优化>
- iOS开发之网络编程--4、NSURLSessionDataTask实现文件下载(离线断点续传下载) <进度值显示优化>
- iOS开发之网络编程--4、NSURLSessionDataTask实现文件下载(离线断点续传下载) <进度值显示优化>
- strut2下载文件的“ <param name="inputName"> tag specified for this action.”异常
- 网站上有一个mp3文件,但是用<a href="my.mp3">下载</a>时,会在播放器里打开,请问我要怎样才能实现点击后下载呢?
- <input type="file" />浏览时只显示指定文件类型
- <input type="file" />浏览时只显示指定文件类型
- struts2文件下载及 <param name="inputName">inputStream</param>的理解
- [原]java专业程序代写(qq:928900200),学习笔记之基础入门<servlet_文件下载>(二十七)
- 导入ASIHTTPRequest 提示<libxml/HTMLparser.h> 找不到头文件
- 实时开发框架Meteor 实际应用系列<一>---文件的上传和下载
- <opencv学习 1>图像文件的读入与显示
- struts2文件下载 <result type="stream">
- <h1>读取配置文件失败</h1>这通常意味着文件中有语法错误,请检查下面显示出的错误。<br /><br /><iframe src="show_config_errors.php" />
- Control Study->AdRotator广告控件显示自定义配置文件中广告以及与DataGrid控件结合使用显示图片(示例代码下载)
- Control Study->AdRotator广告控件显示自定义配置文件中广告以及与DataGrid控件结合使用显示图片(示例代码下载)
- struts2文件下载及 <param name="inputName">inputStream</param>的理解
- 为什么下载文件文件名太长就会被截取,但是用<a href="">就不会有文件名超长的问题?!
- <a>标签点击实现下载文件功能