1一个月linux debian学习 做出了第一个下载软件,支持多线程,断点续传

#include <iostream>
#include <fstream>
#include <sys/socket.h>     //linux
#include <netinet/in.h>   //linux
#include <sys/types.h>  //linux
#include <arpa/inet.h>   //linux
#include <netdb.h>  //linux
#include <string>
#include <sstream>
//用于select
#include <sys/time.h>  //linux
#include <unistd.h>   //linux
#include <iomanip>  //格式化输出 包括的头文件
#include <pthread.h>  //多线程库  linux
#include <list>

#include <cstdio> //用于删除文件 c语言的


using namespace std;
bool FirstOk;
unsigned long DownTolSize;
int overthreadnum;
pthread_mutex_t look=PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t DownLook=PTHREAD_MUTEX_INITIALIZER;
struct FileInfo
{
    unsigned int GetHeadOnly;
    unsigned long Filesize;
    unsigned long NeedDownSize;
    unsigned long Start;
    unsigned long End;
    char FileName[256];
    char Url[1024];
};
class DelaySub{
public:
    DelaySub(unsigned long times){
    time=times;
    FD_ZERO(&fs);
    FD_SET(0,&fs);

//    tv.tv_sec=times / 1000;
//    tv.tv_usec=times % 1000;
    }
   
    void SetTime(unsigned long times){
        time=times;
    }

    void Delay(){
        long tem;
        tem=time/ 1000;
        tv.tv_sec=tem;
        tem=time% 1000 *1000;
        tv.tv_usec=tem; //用于毫秒 微秒转换   改变 微秒级别的 只需要把*1000去掉就可以了
        if(0==time/1000 && 0== time%1000){
        return;}

        select(0,NULL,NULL,NULL,&tv);
       
    }
    int time;   
    fd_set fs;
    struct timeval tv;
};
   
class GetSub
{
    public:
    bool GetLength(string& data,long& Length);
    string GetHostName(string& Url);
    string GetFileName(string& Url);
    unsigned long GetFileLength(string  Path);
};
class SockHttp
{

    public:
    SockHttp(){
        memset(&server,0,sizeof(server));
    }
    ~SockHttp(){
    close(Usock);
    }
    int Usock;
    struct sockaddr_in server;
    int MakeSock();
    bool HttpConnect(string ip,unsigned int port);
    bool HttpSend(string &senddata);
    string  HostToIp(string Host);
    bool HttpSendHead(string& Url,string host,unsigned long Start,unsigned long End=0);
    bool HttpGetHead(string& HeadStr);

};
unsigned long GetSub::GetFileLength(string Path)
{
    fstream file;
    file.open(Path.c_str(),ios::binary|ios::in);
    if(!file){
        return 0;
    }
    file.seekg(0L,file.end);
    unsigned long tem=file.tellg();
    file.close();
    return tem;
}
string GetSub::GetFileName(string& Url)
{
    string tem;
    int a;
    a=Url.rfind("/");
    if(a<0) return "";
    tem=Url.substr(a+1);
    return tem;
}
string GetSub::GetHostName(string& Url)
{
    string tem;
    int first=0;
    first=Url.find("http://");
    if(first<0) return "";
    tem=Url.substr(first+7);
    first=tem.find("/");
    if(first<=0) return "";
    tem=tem.substr(0,first);
    return tem;
}
bool SockHttp::HttpGetHead(string& HeadStr)
{
    char tem[10];
    HeadStr="";
    int a;
    do {
        memset(tem,0,sizeof(tem));
        if(0>recv(Usock,tem,1,0)) return false;
        HeadStr+=tem;
        a=HeadStr.find("/r/n/r/n");
    }while(0>=a);

    return true;
}
bool SockHttp::HttpSendHead(string& Url,string host,unsigned long Start,unsigned long End)
{
    //cout<<Start<<"end "<<End<<endl;
    string senddata;
    senddata="";
    //`    ="GET ";
    stringstream tem(senddata);
    tem<<"GET ";
    //senddata+=Url;
    tem<<Url;
    //senddata+=" HTTP/1.1/r/nRange: bytes=";
    tem<<" HTTP/1.1/r/nRange: bytes=";
    if(0==Start)   tem<<"0"; //senddata+="0";
    else    tem<<Start;//senddata+=Start;
    //senddata+="-";
    tem<<"-";
    if(End!=0)       tem<<End; //senddata+=End;
    else          tem<<""; //senddata+="";
//    senddata+="/r/nHost: ";
    tem<<"/r/nHost: ";
//    senddata+=host;
    tem<<host;
//    senddata+="/r/n/r/n";
    tem<<"/r/n/r/n";
    senddata=tem.str();
    if(0>send(Usock,senddata.c_str(),sizeof(char)*senddata.size(),0)) return false;
//    cout<<senddata<<endl;
    return true;
}
string SockHttp::HostToIp(string Host)
{
    hostent * phost;
    phost=gethostbyname(Host.c_str());
    if(phost==NULL){
        return "";
    }
    in_addr tem;
    memcpy(&tem.s_addr,phost->h_addr,phost->h_length);
    string ip=inet_ntoa(tem);
    return ip;

}
bool SockHttp::HttpSend(string &senddata)
{
    if(0>send(Usock,senddata.c_str(),sizeof(char)*senddata.size(),0)){
        //send err
        return false;
    }
    return true;
}
int SockHttp::MakeSock()
{
    int sock=0;
    sock=socket(AF_INET,SOCK_STREAM,0);
    Usock=sock;
    return sock;
   
}
bool SockHttp::HttpConnect(string ip,unsigned int port)
{
    server.sin_family=AF_INET;
    server.sin_port=htons(port);
    server.sin_addr.s_addr=inet_addr(ip.c_str());
    if(0>connect(Usock,(struct sockaddr*) &server,sizeof(server)))
    {
        //connect err
        return false;
    }
   
    return true;
}
bool GetSub::GetLength(string& data,long& Length)
{
    string tem;
    long first=0 ;
    long sec=0;
    first=data.find("Content-Length:");
    if(first==-1){
        Length=0;
        return false;
    }
    tem=data.substr(first+15);
    sec=tem.find("/n");
    if(sec<=0){
        Length=0;
        return false;
    }
    tem=tem.substr(0,sec-1);
    stringstream sstr;
    sstr<<tem;
    sstr>>Length;
    return true;
}
void *Downthread(void * pin)
{

    struct FileInfo * tempfinfo=(struct FileInfo *)pin;
    struct FileInfo fileinfo;
    memset(&fileinfo,0,sizeof(FileInfo));
    memcpy(&fileinfo,tempfinfo,sizeof(FileInfo));
    GetSub getsub;
    SockHttp httpd;
    int sock;
    sock=httpd.MakeSock();
    string url=fileinfo.Url;    
    string host=getsub.GetHostName(url);

    unsigned int conport=80;
    if(host.find(":")!=-1){
        string temport;
        temport=host.substr(host.find(":")+1);
        stringstream turn(temport);
        turn>>conport;
        host=host.substr(0,host.find(":"));
    }
    string ip=httpd.HostToIp(host);
//    cout<<host<<"  "<<ip<<":"<<conport<<endl;
    DelaySub delay(500);

    unsigned long tt=0;
    std::_Ios_Openmode   openmode; //定义 文件读写模式
    openmode=ios::binary|ios::out|ios::trunc;

    if(fileinfo.GetHeadOnly==0){
        GetSub test;
        tt=test.GetFileLength(fileinfo.FileName);
        if(tt>0&& tt<=fileinfo.NeedDownSize){
            //在这里设置续传机制
            if(tt+1>=fileinfo.NeedDownSize){
                pthread_mutex_lock(&DownLook);
                DownTolSize+=tt;
                pthread_mutex_unlock(&DownLook);

                pthread_mutex_lock(&look);
                overthreadnum++;
                pthread_mutex_unlock(&look);
                cout<<fileinfo.FileName<<"  <download over> ";
                return NULL;
            }
            fileinfo.Start=fileinfo.Start+tt;
            openmode=ios::binary|ios::out|ios::app;
        //    cout<<tt<<endl<<fileinfo.Start<<endl<<fileinfo.End<<endl<<fileinfo.NeedDownSize<<endl;
        }else{
            tt=0;
                }

    }
    if(host=="" || ip==""){
        cout<<"Err When Get Host or Get IP!   After 1s try again!"<<endl;
        delay.Delay();
        pthread_t tid;
        pthread_create(&tid,NULL,Downthread,pin);
        return NULL ;

    }

    if(fileinfo.GetHeadOnly==1){
        cout<<"host:"<<host<<endl;
        cout<<"ip:"<<ip<<endl;
        cout<<endl;
    }
    if(!httpd.HttpConnect (ip,conport)) {
        cout<<"err when Http connect! After 1s try again!"<<endl;   
        delay.Delay();
        pthread_t tid;
        pthread_create(&tid,NULL,Downthread,pin);
        return NULL ;
   
    }

    if(!httpd.HttpSendHead(url, host,fileinfo.Start,fileinfo.End )) {
        cout<<"err when send head! After 1s try again!"<<endl;   
        delay.Delay();
        pthread_t tid;
        pthread_create(&tid,NULL,Downthread,pin);
        return NULL ;
    }
    string head;
    if(!httpd.HttpGetHead(head)){
        cout<<"Err When Get HttpHead! After 1s try again!"<<endl;
        delay.Delay();
        pthread_t tid;
        pthread_create(&tid,NULL,Downthread,pin);
        return NULL;
    }
    string linehead="";
    linehead=head.substr(0,head.find("/n"));
//    cout<<linehead<<endl;
    if( (linehead.find("400"))!=-1|| linehead.find("406")!=-1 || linehead.find("404")!=-1){
        cout<<"send head err:   After 1s try again!"<<endl;//cout<<head<<endl;
        delay.Delay();
        pthread_t tid;
        pthread_create(&tid,NULL,Downthread,pin);
        return NULL ;
    }
    if(fileinfo.GetHeadOnly==1){
    //    cout<<head<<endl;
        long length;
        if(!getsub.GetLength(head,length)){
            cout<<"When Get File Length err! After 1s try again!"<<endl;
            pthread_t tid;
            delay.Delay();
            pthread_create(&tid,NULL,Downthread,pin);
            return NULL ;   
        }
        ((struct FileInfo *)pin)->Filesize=length;
        memcpy(((struct FileInfo *)pin)->FileName,(getsub.GetFileName(url)).c_str(),sizeof(char)*255);
        return NULL;
    }
    ofstream wr;
    wr.open(fileinfo.FileName,openmode);
    if(!wr){
        cout<<"open file err!After 1s try again!"<<endl;
        pthread_t tid;
        delay.Delay();
        pthread_create(&tid,NULL,Downthread,pin);
        return NULL;
    }
    char temdata[1024];
    int tol=0;
    long alltol=0;
//    char aww=(char)13;
    alltol=tt;
    if(alltol>0){
        pthread_mutex_lock(&DownLook);
        DownTolSize+=tt;
        pthread_mutex_unlock(&DownLook);
    }
    do{       
        memset(temdata,0,sizeof(temdata));
        tol=recv(sock,temdata,sizeof(temdata),0);
        if(tol<=0){
            cout<<"下载出现错误! After 1s try again!"<<endl;
            pthread_mutex_lock(&DownLook);
        //    DownTolSize-=alltol;
            pthread_mutex_unlock(&DownLook);
           
            pthread_t tid;
            delay.Delay();
            pthread_create(&tid,NULL,Downthread,pin);
            wr.close();
            return NULL;

        }
        alltol+=tol;
        if(tol>0) wr.write(temdata,tol);
        pthread_mutex_lock(&DownLook);
        DownTolSize+=tol;
        pthread_mutex_unlock(&DownLook);
    /*    单线程可以使用
        cout<<alltol<<"完成:"<< ((double)alltol)/(fileinfo.NeedDownSize) *100<<"%                  "<<aww<<flush;
*/    }while(alltol<=fileinfo.NeedDownSize-1);
    wr.close();
    cout<<fileinfo.FileName<<" <download over!>  "<<endl;
    pthread_mutex_lock(&look);
    overthreadnum++;
    pthread_mutex_unlock(&look);
    FirstOk=true;

}

int main(int argc,char * argv[])
{
    if(argc==1)
    {
        cout<<"usage: down http://"<<endl;
        return -1;
    }
    string url;
    url=argv[1];
er:
    FirstOk=false;

    unsigned long threadnum=8;  //线程数目:w
    struct FileInfo ss;
    memset(&ss,0,sizeof(FileInfo));
    memcpy((ss.Url),url.c_str(),sizeof(char)*url.size());
    ss.GetHeadOnly=1;
    ss.Start=0;
    FirstOk=false;
    Downthread((void*)&ss);   

    DelaySub delay(100);
    while(FirstOk)
    {
        delay.Delay();
    }
    if(ss.Filesize==0){
        goto er;
    }
    cout<<"File Name: "<<right<< setw(12) <<ss.FileName<<endl;
    cout<<"File Size:"<<right<<setw(12)<<ss.Filesize<<endl;

    list<struct FileInfo*> downlist;

    struct FileInfo* pfi;
    unsigned long threaddownsize=ss.Filesize /threadnum;
    overthreadnum=0;
    string temname;
    pthread_t oo[10];
    pthread_mutex_init(&look,NULL);
    pthread_mutex_init(&DownLook,NULL);
    for(unsigned long i=0;i<threadnum;i++)
    {
        temname="";
        stringstream sttem(temname);
        pfi=new (struct FileInfo);
        memset(pfi,0,sizeof(FileInfo));
        pfi->GetHeadOnly=0;
        pfi->Start=i*threaddownsize;           //start
       
        if((i+1)==threadnum) {
            pfi->End=0;         //
            pfi->NeedDownSize=ss.Filesize-i*threaddownsize;            //needdownsize
        }
        else {
            pfi->End=(i+1)*threaddownsize-1;    // end
            pfi->NeedDownSize=pfi->End-pfi->Start+1;            //needdownsize
        }
        sttem<<ss.FileName;
        sttem<<"_";
        sttem<<i;
        temname=sttem.str();
        memcpy(pfi->FileName,temname.c_str(),sizeof(char)*temname.size());  //filename
        pfi->Filesize=ss.Filesize;                //filesize
        memcpy(pfi->Url,url.c_str(),sizeof(char)*url.size());  //ur;
        downlist.push_back(pfi);
        int err=pthread_create(&oo[i],NULL,Downthread,(void *)pfi);
        if(0!=err){
            cout<<"creat err"<<endl;
        }
    }

    char chw=(char)13;
    unsigned long speed;
    speed=0;
    unsigned long realspeed=0;
    while(overthreadnum!=threadnum)
    {
        delay.Delay();
        realspeed=((DownTolSize-speed)*5/1024)==0?realspeed:((DownTolSize-speed)*5/1024);
        cout<<"下载进度:"<<right<<setw(12)<< (double)DownTolSize /ss.Filesize *100 <<"%   "<<chw<<"速度:"<<right<<setw(10)<< realspeed<<"kb/s";
        speed=DownTolSize;
    }
    cout<<endl;
    cout<<"共下载:  "<<DownTolSize<<endl;
    cout<<"总大小: "<<ss.Filesize<<endl;


    fstream writew;
    fstream readw;
    char data[1024*10];
    long getcount=0;
    writew.open(ss.FileName,ios::out|ios::binary|ios::trunc);
    if(writew){

        for(list<struct FileInfo *>::iterator p=downlist.begin();p!=downlist.end();p++){
            readw.open((*p)->FileName,ios::in|ios::binary);
            if(readw){
                while(!readw.eof())
                {
                    readw.read(data,sizeof(data));
                    getcount=readw.gcount();
                    writew.write(data,getcount);
                }
               
            readw.close();
            remove((*p)->FileName);
            }else{
                cout<<"read "<<(*p)->FileName<<"  err"<<endl;
            }               
        }
    writew.close();
    }else{   
        cout<<"open  "<<ss.FileName<<"  err!"<<endl;
    }

    for(list<struct FileInfo *>::iterator p=downlist.begin();p!=downlist.end();p++){
        delete (*p);
    }
   
    cout<<endl<<"complete file: "<<right<<setw(12)<<ss.FileName<<endl;
    cout<<"end"<<endl;
    return 0;
}


代码写的不好!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值