#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;
}
代码写的不好!