linux c++下载http文件并显示进度<转>

来源:互联网 发布:c语言标准库函数源码 编辑:程序博客网 时间:2024/05/17 23:38
#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 内的有两处:

 char message[18000] = {0};
 char messagetop[18000]={0};
可能在运行的时候造成栈溢出,所以最好是修改为动态申请空间。
另外还有一处就是GetFileSize() 内 问题同上。

 

2. 

在DownloadFile() 内的写文件中:

里面有个for循环:for(int i = hsize -1; i<msglen ; i++)

我在亲自测试的发现 hsize - 1 会使文件保存大小跟原始文件有出入。于是暂时改成了 for(int i = hsize ; i<msglen ; i++) 

不知道对于其他类型文件是否应该 做 -1 操作。待以后再测一测看看。

0 0
原创粉丝点击