📄 zhuftp.cpp
字号:
#include "zhuftp.h"//#define TESTZHUFTP #ifdef TESTZHUFTP#include <signal.h>#endif#if 1#define Dprintf printf#else#define Dprintf #endifFtpZhu::FtpZhu():FtpStatus(FTP_DISCONNECTED),CmdSocket(0),Timeout(20),lasttime(0){}FtpZhu::~FtpZhu(){ if(CmdSocket!=0) { close(CmdSocket); }}/**检查是否超时.flag:更新时间标志,0查询时间,1,更新时间.返回:0超时,1正常.*/int FtpZhu::CheckTime(int flag){ time_t ctime; if(lasttime==0 || flag==1) { lasttime=time(NULL); return 1; } if(flag==0) { ctime=time(NULL); if(ctime-lasttime>Timeout) return 0; } return 1;}/**设置超时时间,单位秒,初始默认为20秒*/void FtpZhu::SetTimeout(int interval){ Timeout=interval;}/**发送FTP命令.返回:ftp服务器的返回码.参数:sockfd连接ftp的socket. cmd发送的命令字符串.*/int FtpZhu::SendFtpCommand(int sockfd,const char*cmd){ int ret; char val[4]; if((ret=send(sockfd,cmd,strlen(cmd),0))==-1) { perror("ftp send command"); } Dprintf("CLIENT:: %s\n",cmd); //receive data from server memset(recvbuffer,0,sizeof(recvbuffer)); if((ret=recv(sockfd,recvbuffer,sizeof(recvbuffer),0))==-1) perror("ftp recv command return"); Dprintf("SERVER:: %s\n",recvbuffer); strncpy(val,recvbuffer,3); val[3]='\0'; ret=atoi(val); Dprintf("Ret is %d\n",ret); return ret;}/**登录ftp服务器.ServerIp:服务器IP,如192.168.0.59uname:用户名password:密码返回:ftp服务器的返回码.*/int FtpZhu::ConnectServer(const char *ServerIp,const char*uname,const char*password){ int ret; char ftpcmd[64]; if((CmdSocket=socket (AF_INET,SOCK_STREAM,0))<0) { perror("ftp socket connect"); return -1; } //fill struct sockaddr_in bzero(&cmdaddr,sizeof(cmdaddr)); cmdaddr.sin_family=AF_INET; cmdaddr.sin_port=htons(21); cmdaddr.sin_addr.s_addr=inet_addr(ServerIp); //try connecting if (connect(CmdSocket,(struct sockaddr*)&cmdaddr,sizeof(cmdaddr))<0) { perror("connect"); return -1; } //接收欢迎消息 if((recv(CmdSocket,recvbuffer,sizeof(recvbuffer),0))==-1) perror("Connect Message Failed!"); else Dprintf("SERVER:: %s\n",recvbuffer); sprintf(ftpcmd,"USER %s\r\n",uname); ret=SendFtpCommand(CmdSocket,ftpcmd); sprintf(ftpcmd,"PASS %s\r\n",password); ret=SendFtpCommand(CmdSocket,ftpcmd); sprintf(ftpcmd,"TYPE I\r\n"); ret=SendFtpCommand(CmdSocket,ftpcmd); FtpStatus=FTP_CONECTED; return 0;}/**通过Ftp获取文件. 支持断点续传,目前尚未支持超时控制.可由外部信号中断. remotepath:远程ftp服务器目录 localpath:本机目录 filename:要下载的文件名. 返回:0成功,-1失败.*/int FtpZhu::GetFile(const char *remotepath,const char *localpath,const char*filename){ int ret,datasocket,dataport,recvlen,filesize; struct sockaddr_in data_addr; char databuf[1024],cmdbuf[128],*val; char remotename[128],localname[128],*tmpbuf; FILE *fp; struct stat files; int receiveend; //检测ftp必须连接上服务器 if(FtpStatus != FTP_CONECTED) return -1; //检查本地文件是否已经存在,如果不存在则创建,如果无法创建将返回错误 sprintf(localname,"%s/%s",localpath, filename); if ((ret = stat(localname, &files)) == -1) filesize=0; else filesize=files.st_size; if((fp=fopen(localname,"a"))==NULL) { perror("Open local file failed!"); return -1; } fseek(fp,0,SEEK_END); //获得数据端口 ret=SendFtpCommand(CmdSocket,"PASV\r\n"); if (ret != 227) return -1; val=strtok(recvbuffer,","); for(int i=0;i<4;i++) val=strtok(NULL,","); dataport=atoi(val); val=strtok(NULL,")"); dataport=dataport*256+atoi(val); //Dprintf("data port is %d\n",dataport); if((datasocket=socket (AF_INET,SOCK_STREAM,0))<0) { perror("socket"); return -1; } //fill struct sockaddr_in memcpy(&data_addr,&cmdaddr,sizeof(data_addr)); data_addr.sin_port=htons(dataport); //try connecting if (connect(datasocket,(struct sockaddr*)&data_addr,sizeof(data_addr))<0) { perror("dataport connect"); return -1; } //设置接收文件的上次下载位置 sprintf(cmdbuf,"REST %d\r\n",filesize); ret=SendFtpCommand(CmdSocket,cmdbuf); sprintf(remotename,"%s/%s",remotepath,filename); sprintf(cmdbuf,"RETR %s\r\n",remotename); ret=SendFtpCommand(CmdSocket,cmdbuf); if(ret==150) { receiveend=0; //检查是否收到226,如果收到则表示数据下载完成. tmpbuf=strchr(recvbuffer,'\n'); tmpbuf++; if(strcmp(tmpbuf,"")) { val=strtok(tmpbuf," "); if (!strcmp(val,"226")) receiveend=1; } FtpStatus=FTP_TRANSING; do { do//开始下载文件 { recvlen=recv(datasocket,databuf,sizeof(databuf),0); if(recvlen==-1) { perror("ftp recv data return"); break; } else if(recvlen==0) { if(receiveend==1)//如果是最后的数据,则退出 goto DownloadFileEnd; else//离开循环去检查命令端口的数据 break; } else { fwrite(databuf,1,recvlen,fp); fflush(fp); CheckTime(1); } }while(FtpStatus==FTP_TRANSING); //等待下载文件结束 if(FtpStatus==FTP_STOPPING) break; if(recv(CmdSocket,recvbuffer,sizeof(recvbuffer),0)==-1) perror("ftp recv cmd return"); Dprintf("SERVER:%s",recvbuffer); val=strtok(recvbuffer," "); if (!strcmp(val,"226")) receiveend=1; if(CheckTime(0)==0) break; }while(FtpStatus==FTP_TRANSING); //用户终止下载 if(FtpStatus==FTP_STOPPING) { ret=SendFtpCommand(CmdSocket,"ABOR\r\n"); } }DownloadFileEnd: FtpStatus=FTP_CONECTED; //关闭临时文件 fclose(fp); shutdown(datasocket,0); return 0;}/**上传文件,暂不支持断点续传 remotepath:远程ftp服务器目录 localpath:本机目录 filename:要上传的文件名. 返回:0成功,-1失败.*/int FtpZhu::PutFile(const char *remotepath,const char *localpath,const char*filename){ int ret,datasocket,dataport,sendlen,recvlen; struct sockaddr_in data_addr; char databuf[1024],cmdbuf[128],*val; char tmpbuf[1200],*tmpptr,*thisstr,*nextstr; char localname[128]; FILE *fp; int fileoffset; ftpfiledis fdis; //检测ftp必须连接上服务器 if(FtpStatus!=FTP_CONECTED) return -1; //获得数据端口 ret=SendFtpCommand(CmdSocket,"PASV\r\n"); if(ret!=227) return -1; val=strtok(recvbuffer,","); for(int i=0;i<4;i++) val=strtok(NULL,","); dataport=atoi(val); val=strtok(NULL,")"); dataport=dataport*256+atoi(val); //Dprintf("data port is %d\n",dataport); if((datasocket=socket (AF_INET,SOCK_STREAM,0))<0) { perror("socket"); return -1; } //fill struct sockaddr_in memcpy(&data_addr,&cmdaddr,sizeof(data_addr)); data_addr.sin_port=htons(dataport); //try connecting if (connect(datasocket,(struct sockaddr*)&data_addr,sizeof(data_addr))<0) { perror("dataport connect"); return -1; } //检查本地文件是否已经存在,如果不存在则创建 sprintf(cmdbuf,"CWD %s\r\n",remotepath); ret=SendFtpCommand(CmdSocket,cmdbuf); //发送LIST命令获得文件列表 sprintf(cmdbuf,"LIST \r\n"); ret=SendFtpCommand(CmdSocket,cmdbuf); //接收文件列表 memset(tmpbuf,0,sizeof(tmpbuf)); fileoffset=0;//如果找不到文件,从0开始. do//开始下载文件 { recvlen=recv(datasocket,databuf,sizeof(databuf),0); if(recvlen==-1) { perror("ftp recv data return"); break; } else if(recvlen==0) { if(CheckTime(0)==0) break; } else { printf("%s",databuf); strcat(tmpbuf,databuf); thisstr=tmpbuf; tmpptr=strchr(tmpbuf,'\n'); while(tmpptr!=NULL) { *tmpptr='\0'; nextstr=(char*)(tmpptr+1); if(strcmp(thisstr,"")!=0) { sscanf(thisstr,"%s%d%s%s%d%s%d%s%s",&fdis.prior,&fdis.usern,&fdis.username,&fdis.groupname ,&fdis.filesize,&fdis.date,&fdis.day,&fdis.time,&fdis.filename); if(strcmp(fdis.filename,filename)==0) { fileoffset=fdis.filesize; goto findoffset; } } thisstr=nextstr; tmpptr=strchr(thisstr,'\n'); } //保存上次未解析完的字符串. strcpy(tmpbuf,thisstr); } }while(FtpStatus==FTP_TRANSING); findoffset: //等待数据传送完成. if(recv(CmdSocket,recvbuffer,sizeof(recvbuffer),0)==-1) perror("ftp recv cmd return"); Dprintf("SERVER:%s",recvbuffer); //val=strtok(recvbuffer," "); shutdown(datasocket,1); close(datasocket); Dprintf("FILEOFFSET is %d\n",fileoffset); //再次获得数据端口 ret=SendFtpCommand(CmdSocket,"PASV\r\n"); if(ret!=227) return -1; val=strtok(recvbuffer,","); for(int i=0;i<4;i++) val=strtok(NULL,","); dataport=atoi(val); val=strtok(NULL,")"); dataport=dataport*256+atoi(val); //Dprintf("data port is %d\n",dataport); if((datasocket=socket (AF_INET,SOCK_STREAM,0))<0) { perror("socket"); return -1; } //fill struct sockaddr_in memcpy(&data_addr,&cmdaddr,sizeof(data_addr)); data_addr.sin_port=htons(dataport); //try connecting if (connect(datasocket,(struct sockaddr*)&data_addr,sizeof(data_addr))<0) { perror("dataport connect"); return -1; } sprintf(localname,"%s/%s",localpath,filename); fp=fopen(localname,"rb"); fseek(fp,fileoffset,SEEK_SET); sprintf(cmdbuf,"REST %d\r\n",fileoffset); ret=SendFtpCommand(CmdSocket,cmdbuf); sprintf(cmdbuf,"STOR %s\r\n",filename); ret=SendFtpCommand(CmdSocket,cmdbuf); if(ret!=150) return -1; FtpStatus=FTP_TRANSING; while(!feof(fp) && FtpStatus==FTP_TRANSING)//开始上传文件 { sendlen=fread(databuf,1,sizeof(databuf),fp); if(sendlen==-1) { perror("ftp send data return"); break; } else { ret=send(datasocket,databuf,sendlen,0); if(ret==-1) { perror("Upload file failed!"); break; } } } shutdown(datasocket,1); close(datasocket); if(recv(CmdSocket,recvbuffer,sizeof(recvbuffer),0)==-1) perror("ftp recv cmd return"); Dprintf("SERVER:%s",recvbuffer); val=strtok(recvbuffer," "); if (!strcmp(val,"226")) goto returnroot; //用户终止上传 if(FtpStatus==FTP_STOPPING) { ret=SendFtpCommand(CmdSocket,"ABOR\r\n"); return -1; }returnroot: FtpStatus=FTP_CONECTED; //关闭数据文件 fclose(fp); //返回根目录 sprintf(cmdbuf,"CWD /\r\n",remotepath); ret=SendFtpCommand(CmdSocket,cmdbuf); return 0;}/**断开ftp连接.*/int FtpZhu::Disconnect(){ if(FtpStatus==FTP_TRANSING) FtpStatus=FTP_STOPPING; if(FtpStatus==FTP_CONECTED) { shutdown(CmdSocket,2); close(CmdSocket); FtpStatus=FTP_DISCONNECTED; } SendFtpCommand(CmdSocket,"QUIT\r\n"); return 0;}/**获取当前ftp状态.*/int FtpZhu::GetFtpStatus(){ return FtpStatus;}#ifdef TESTZHUFTPstatic FtpZhu fz;static void SignalHandle(int signo){ if(signo==SIGALRM) { Dprintf("Receive signal alarm!\n"); fz.Disconnect(); } return ;}//测试ftpint main(){ //fz.ConnectServer("20.3.254.254","mediabus","zhu"); fz.ConnectServer("192.168.0.159","mediabus","zhu"); //signal(SIGALRM,SignalHandle); //alarm(12); Dprintf("Now Test Downloading Files\n"); fz.GetFile("media",".","zhu25.mpg"); sleep(3); Dprintf("Now Test Uploading Files\n"); fz.PutFile("tmp",".","zhu25.mpg"); sleep(1); fz.Disconnect(); return 1;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -