本文实例为大家分享了C++文件上传下载的实现代码,供大家参考,具体内容如下
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/timeb.h>#include <sys/ioctl.h>#include <string.h> #include <fcntl.h>#include <sys/wait.h>#include <sys/socket.h>#include <errno.h> #include <sys/types.h>#include <sys/stat.h>#include <unistd.h> #include <netinet/in.h>#include <netinet/tcp.h>#include <arpa/inet.h> #ifndef __TCPfile_C__#define __TCPfile_C__ #include "libfunc.h"#include "vAPI_log.h" #define CMDhead 6 // 通信报文头信息长度#define CMDINFO 6 // 空值命令 PUT GET#define CMD #define MAXKB 16#define NCMD 32#define Nfile 128 // tcp 通信命令行缓冲区typedef struct tcpCmd { int len; // 命令行长度 char cmd[NCMD+1]; // 命令行缓冲区} tcpCmd; struct tcpBuffer { int rlen; // 接收数据长度 int wlen; // 发送数据长度 char rcvcmd[NCMD+1]; // 接收命令域数据 char sndcmd[NCMD+1]; // 接收命令域数据 tcpCmd rCmd ; // 接收缓冲区 tcpCmd sCmd ; // 发送缓冲区 char buff[1024 * MAXKB + 64 + 1 ]; // 报文缓冲区,包含命令控制串和实际报文数据 } ncb; // ////////////////////////////////////////////////////////////////////////////////////////////// ////// //// 根据报文头数据要求,接收一个通信数据。 //// 程序首先按照要求读取 headlen 长度的长度包数据,然后再次从网络上读取真正长度的数据包。 //// //// 数据接收函数分两次进行处理,返回数据 sData 中已经不再包含 6位通信长度数据。 //// ///////////////////////////////////////////////////////////////////////////////////////////// ////int tcp_readbuf(int headlen,int sfd,char * sData,int MaxLen,int sTime){ int iRet = 0; int left_bytes,thisRead,sLen; char *ptr = sData; struct timeval tv; fd_set rfds; char temp[ NCMD + 1 ]; tv.tv_sec = (long )sTime ; tv.tv_usec = 0; FD_ZERO(&rfds); FD_SET(sfd,&rfds); do{ iRet = select(sfd+1,&rfds,NulL,&tv) ; }while (iRet < 0 && errno == EINTR ); if(iRet == 0){ wLog(LOGERROR,"tcp_readbuf select 延时[%d] 结束,faile [%d,%s]",sTime,errno,strerror(errno) ); return -1; } // 接受控制命令序列 memset(temp,0x00,sizeof (temp)); thisRead = read(sfd,temp,headlen); if( temp[0]=='0' )sLen = atoi(temp); else sLen = 0; if(thisRead != headlen && sLen ){ wLog(LOGERROR,"读取通信报文长度[%s]失败,strerror(errno) ); return -1; } if(sLen < 1 || sLen > MaxLen ){ if(sLen > MaxLen ) wLog(LOGERROR,"报文长度[%s]错误,数据非法. ",temp ); return -1; } left_bytes = sLen; while( left_bytes > 0 ){ if( (thisRead = read(sfd,ptr,left_bytes)) == 0) break ; if(thisRead < 0 ){ if( errno == EINTR ) continue; break; } left_bytes -= thisRead; ptr += thisRead; } if(left_bytes && ptr != sData ) wLog(LOGERROR,"[tcp_readbuf [%d] faile [%d,sLen,strerror(errno) ); /* 数据没有处理完时,程序打印错误日志信息 */ return(sLen-left_bytes);} //// 数据发送程序,在指定的延时内将指定长度的数据包发送到 sfd 上。// 发送数据需要将报文长度保存在 sData 中,发送长度比实际的报文多出长度域 6字节//int tcp_writebuf(int sfd,int sLen,thisWrite; char *ptr = sData; fd_set wfds; struct timeval tv; FD_ZERO(&wfds); FD_SET(sfd,&wfds); do{ iRet = select(sfd+1,&wfds,&tv) ; }while (iRet < 0 && errno == EINTR ); if(iRet==0){ wLog(LOGERROR,"tcp_writebuf select 延时[%d] 结束,strerror(errno) ); return -1; } // 检查通信链路的 写状态 left_bytes=sLen; while(left_bytes >0 ){ if( (thisWrite = write(sfd,left_bytes)) == 0) break ; if(thisWrite < 0 ){ if( errno == EINTR ) continue; break; } left_bytes -= thisWrite; ptr += thisWrite; } // 将数据发送到通信端口 if(left_bytes && ptr != sData ) wLog(LOGERROR,"[tcp_sendbuf left_bytes[%d] faile [%d,left_bytes,strerror(errno) ); return(sLen-left_bytes);} // ============================= 客户端使用 文件发送程序 ================================= ////// //// socket 方式文件发送程序,根据输入的 netinfo 建立通信通道,然后按照以下要求发送文件 //// PUT100 发送文件基本信息 //// PUT200 发送文件内容,根据要求循环执行,...... //// PUT300 数据发送结束 //// //// ======================================================================================= //// int cli_put_sendfile(char *netinfo,char *localfile,char *remotefile,int blockSize,int timeout){ int sfd,fd; struct stat sb; int iRet ; int chkflg = 0 ; int maxBlk,blknum = 0; long start; long fsize; sfd = fd = -1; start = time(NulL); sfd = make_tcpConnect (netinfo); // 申请 socket 描述符,使用 connect () 建立到服务器的连接通道 if(sfd < 0 ) { wLog(LOGERROR,"建立到[%s]连接失败 error [%d,netinfo,strerror(errno) ); return -4; } wLog(LOGINFO,"成功建立到[%s]发送通道[%d]",sfd ); fd = open(localfile,O_RDONLY); if(fd == -1){ wLog(LOGERROR,"本地文件[%s]打开失败 error [%d,localfile,strerror(errno) ); close (sfd ); return -3; } if (fstat(fd,&sb) < 0) { wLog(LOGERROR,"取[%s]文件信息失败 error [%d,strerror(errno) ); chkflg = -3; goto cli_put_sendfile_END; } fsize = sb.st_size; if(blockSize > 1024 * MAXKB ) blockSize = 1024 * MAXKB ; if(blockSize < 1024 ) blockSize = 1024; // 显示本地文件的基本信息 wLog(LOGINFO,"成功打开本地文件[%s],size[%ld] ",fsize ); maxBlk = (int ) ( (fsize ) / blockSize) ; // 计算本文件的最大传输次数 if( fsize % blockSize ) maxBlk += 1; // 不足整块的数据,需要按一块进行处理。 memset(&ncb,sizeof (struct tcpBuffer)); // 准备发送文件控制命令串,告诉对方准备发送文件的基础信息 ncb.wlen = snprintf(ncb.buff+25,sizeof(ncb.buff)-1,"%s:%010ld:%010d:%010d",remotefile,fsize,blockSize,maxBlk ); sprintf(ncb.sndcmd,"%06d%-16s%1s%2s",ncb.wlen+19,"PUT100fileINFO","1","00"); memcpy(ncb.buff,ncb.sndcmd,25); ncb.wlen += 25; iRet = tcp_writebuf (sfd,ncb.buff,ncb.wlen,timeout); if(iRet != ncb.wlen){ wLog(LOGERROR,"发送[%d] [%s]失败 error [%d,strerror(errno) ); chkflg = -2; goto cli_put_sendfile_END; } wLog(LOGINFO,"发送报文头[%d] [%s]成功",ncb.buff ); ncb.rlen = tcp_readbuf(6,sfd,ncb.rcvcmd,19,timeout); if(ncb.rlen != 19 || memcmp(ncb.rcvcmd+17,"00",2)){ wLog(LOGERROR,"远程保存[%s]失败 error [%d,"接到返回数据 [%s]成功",ncb.rcvcmd ); // 循环将本地文件全部发送完毕 while ( 1 ){ blknum ++; memset(&ncb,sizeof (struct tcpBuffer )); ncb.rlen = read (fd,ncb.buff+25,blockSize ); if(ncb.rlen < 1 ) break ; // 本地文件已经发送结束 sprintf (ncb.sndcmd,"%06dPUT200BLK%07d%1s%2s",ncb.rlen+19,blknum,"00"); memcpy(ncb.buff,25); ncb.rlen += 25; iRet = tcp_writebuf (sfd,ncb.rlen,timeout); if(iRet != ncb.rlen ){ wLog(LOGERROR,"发送 [%s] 失败 error [%d,strerror(errno) ); chkflg = -1; goto cli_put_sendfile_END; } if( blknum == 1 || blknum == maxBlk ) wLog(LOGINFO,"发送数据[%d] [%s]成功",ncb.sndcmd ); iRet = tcp_readbuf(6,timeout); if(iRet != 19 || memcmp(ncb.rcvcmd+ 17,2)){ wLog(LOGERROR,"远程接收 [%s] 失败 error [%d,strerror(errno) ); chkflg = -1; goto cli_put_sendfile_END; } } memset(&ncb,sizeof (struct tcpBuffer )); ncb.wlen = snprintf (ncb.sndcmd,sizeof (ncb.sndcmd )-1,"%-16s%1s%2s","PUT300fileOVER","00" ); sprintf(ncb.buff,"%06d%s",ncb.sndcmd ); iRet = tcp_writebuf (sfd,ncb.wlen+6,timeout); if(iRet != ncb.wlen + 6 ){ wLog(LOGERROR,"发送 fileOver 失败 error [%d,strerror(errno) ); chkflg = -1; goto cli_put_sendfile_END; } wLog(LOGINFO,iRet,ncb.sndcmd ); iRet = tcp_readbuf(6,timeout); if(iRet != 19 || memcmp(ncb.rcvcmd+17,"远程接收 fileOver 失败 error [%d,"接到返回数据[%s]成功",ncb.rcvcmd ); wLog(LOGINFO,"传输[%s]-->[%s] [%d]块,共 [%ld]字节,耗时 %ld 秒\n\n",time(NulL) - start ); cli_put_sendfile_END: if(sfd > 0) close(sfd); if(fd > 0) close(fd); // 关闭本文描述符和通信连接通道描述符 return chkflg;} // ============================ 服务端使用 文件传输程序 ================================= ////// //// socket 文件接收服务程序,对收到的通信报文进行分析。 //// 在收到 PUT100 命令后,将该数据域中的文件名称与本地路径拼写得到完整的文件 //// 路径信息,打开本地文件。 //// 对 PUT200 数据域传输来的数据保存到本地文件中。 //// 收到 PUT300 命令,关闭本地文件,传输过程结束。 //// //// 文件传输服务端程序: //// sfd 在 accept() 后获取的新的客户端连接通道描述符 //// path 准备保存本地文件的路径信息 //// filename 根据接收报文中的文件名称与本地路径拼串而得到的返回文件信息 //// timeout 数据传输需要使用的延时参数 //// //// 返回数据: //// 0 ---- 文件接收成功 //// -2 -- 文件无法创建,打开文件名称失败 //// -1 -- 文件内容内容保存失败 //// ====================================================================================== ////int srv_put_recvfile(int sfd,char *path,char *filename,int timeout ){ int fd = -1; int blknum = 0,maxBlk=0 ; char tfile[Nfile+1],bfile[Nfile+1]; char *ptr; long fsize = 0; int chkflg = 0; memset(tfile,sizeof(tfile)); while ( 1 ){ memset(&ncb,sizeof (struct tcpBuffer)); ncb.rlen = tcp_readbuf (6,timeout); if(ncb.rlen < 0 ) break ; memcpy(ncb.sndcmd + 6,19); if(memcmp(ncb.buff,"PUT",3) ) { wLog(LOGERROR,"接收命令序列 [%s] 错误 ,程序退出. ",ncb.sndcmd+6 ); memcpy(ncb.rcvcmd+23,"01",2); chkflg = -3; } switch (Nstr_int(ncb.buff + 3,3)){ // 获取 PUT 后面的命令控制字,下面分析该控制字进行工作 case 100 : // 开始接收文件,打开本地文件 wLog(LOGINFO,"接收管理报文[%s]成功",ncb.buff ); // 对于接收到的第一条命令,打印该控制命令的全部内容 ptr = strchr(ncb.buff,':'); if(ptr) memcpy(tfile,ncb.buff+19,ptr - (char *)ncb.buff - 19); else strcpy(tfile,ncb.buff+19); // 获取传输来的文件名称 ptr = strrchr(tfile,'/'); if(ptr) strcpy(bfile,ptr+1); else strcpy(bfile,tfile); // 检查传输来文件名称中的路径信息,得到基本文件名称,将前面的路径 // 信息全部剔除,以保证本地文件的安全。 if( (ptr = strrchr(ncb.buff,':') ) != NulL ) maxBlk = atoi (ptr +1); if( path ) sprintf(filename,"%s/%s",path,bfile); else strcpy(filename,bfile ); // 与本地保存路径拼串,获得本地文件名称 fd = open(filename,O_CREAT|O_WRONLY|O_Trunc,0666 ); if(fd < 0 ) { wLog(LOGERROR,"生成本地文件 [%s] 失败 error [%d,filename,strerror(errno) ); memcpy(ncb.rcvcmd+23,2); chkflg = -2; } // 对需要保存的本地文件,使用清空方式,创建新文件,既是该文件已经存在 // 也可以保证数据处理 wLog(LOGINFO,"创建本地文件[%s]成功",filename ); break ; case 200 : // 保存文件内容 blknum ++; maxBlk --; if(blknum == 1 || !maxBlk )wLog(LOGINFO,"接收数据[%s]成功",ncb.sndcmd+6 ); ncb.wlen = write(fd,ncb.rlen - 19); if(ncb.wlen != ncb.rlen - 19 ) { memcpy(ncb.sndcmd + 23,2); chkflg = -1; } else fsize += ncb.wlen ; break ; case 300 : // 文件传输结束 if( !maxBlk ) wLog(LOGINFO," 文件[%s]成功接收,共 [%d] 传输块 ",blknum ); else wLog(LOGERROR,"文件[%s]接收结束,差错 [%d] 传输块 ",maxBlk ); close(fd); chkflg = 1; break ; } memcpy(ncb.sndcmd,"000019",6); ncb.sndcmd [22]='2'; ncb.wlen = tcp_writebuf (sfd,25,timeout); if(ncb.wlen != 25 ){ wLog(LOGERROR,"发送返回信息 [%s] 失败 error [%d,ncb.sndcmd + 6,strerror(errno) ); } if(chkflg ) break ; } if(fd) close (fd); wLog(LOGINFO,"成功接收[%s]文件,共 [%ld] 字节",fsize ); return chkflg ;} // ============================= 客户端使用 多文件发送程序 =============================== ////// //// socket 方式文件发送程序,根据输入的 netinfo 建立通信通道,然后按照以下要求发送文件 //// PUT100 发送文件基本信息 //// PUT200 发送文件内容,根据要求循环执行,...... //// PUT300 数据发送结束 //// //// ======================================================================================= //// //// 在建立好的文件传输通道上,将一个文件数据发送到服务端,传输后,不需要关闭传输通道。//int cli_mput_sendfile(int sfd,int timeout ){ int fd; struct stat sb; int iRet ; int chkflg = 0 ; int maxBlk,blknum = 0; char *ftr; long start; long fsize; fd = -1; start = time(NulL); fd = open(localfile,"取[%s]基本信息失败 error [%d,strerror(errno) ); chkflg = -3; goto mSend_END; } fsize = sb.st_size; if(blockSize > 1024 * MAXKB ) blockSize = 1024 * MAXKB ; if(blockSize < 1024 ) blockSize = 1024; wLog(LOGINFO,fsize ); maxBlk = (int ) ( (fsize ) / blockSize) ; // 计算本文件的最大传输次数 if( fsize % blockSize ) maxBlk += 1; memset(&ncb,sizeof (struct tcpBuffer)); ftr = strrchr( remotefile,'/'); ncb.wlen = snprintf(ncb.buff+25,ftr ? ftr +1 : remotefile,strerror(errno) ); chkflg = -2; goto mSend_END; } wLog(LOGINFO,ncb.rcvcmd ); while ( 1 ){ blknum ++; memset(&ncb,strerror(errno) ); chkflg = -1; goto mSend_END; } if( blknum == 1 || blknum == maxBlk ) wLog(LOGINFO,strerror(errno) ); chkflg = -1; goto mSend_END; } } memset(&ncb,strerror(errno) ); chkflg = -1; goto mSend_END; } wLog(LOGINFO,time(NulL) - start ); mSend_END: if(fd > 0) close(fd); // 关闭本文描述符和通信连接通道描述符 return chkflg; } // ============================================= 多文件处理函数 ====================================== //// //// //// 多文件发送服务程序,本程序对使用 ":" 分隔的文件信息自动进行分解,然后将每一个文件 //// 使用上述函数完成推送工作,在啊全部文件发送完毕后,程序将发出 PUT500 传输结束命令。 //// ///////////////////////////////////////////////////////////////////////////////////////////////////////////int cli_putm_sendfile(char *netinfo,char *sLocalfile,int timeout){ int sfd; int iRet ; int chkflg = 0 ; struct cli_putm_sendfile{ char lfile[Nfile+1]; // 本地文件名称 char rfile[Nfile+1]; // 远程文件名称 }mSnd; char *qList,*ptr ; char *ftr; int fnum = 0; long start ; sfd = -1; start = time(NulL); sfd = make_tcpConnect (netinfo); // 使用 connect () 建立到服务器的连接通道 if(sfd < 0 ) { wLog(LOGERROR,"建立到[%s]文件传输通道失败 error [%d,sfd ); qList = sLocalfile; ptr = strchr(qList,':'); while(qList != NulL) { memset(&mSnd,sizeof(mSnd)); strncpy(mSnd.lfile,qList,ptr - qList); ftr = strrchr(mSnd.lfile,'/'); strcpy(mSnd.rfile,ftr ? ftr + 1 : mSnd.lfile ); iRet = cli_mput_sendfile(sfd,mSnd.lfile,mSnd.rfile,timeout ); if( iRet == 0 ) fnum ++ ; qList = ptr + 1; ptr = strchr(qList,':'); } // 对输入的文件名称进行分解,调用 cli_mput_sendfile() 函数进行数据发送。 memset(&ncb,"PUT500FTPOVER",timeout); if(iRet != ncb.wlen + 6 ) { wLog(LOGERROR,2)) { wLog(LOGERROR,"共 [%d]个文件,fnum,time(NulL) - start ); cli_put_sendfile_END: if(sfd > 0) close(sfd); // 关闭本文描述符和通信连接通道描述符 return chkflg;} // ============================ 服务端使用 多文件传输程序 =============================== ////// //// socket 文件接收服务程序,对收到的通信报文进行分析。 //// 在收到 PUT100 命令后,将该数据域中的文件名称与本地路径拼写得到完整的文件 //// 路径信息,打开本地文件。 //// 对 PUT200 数据域传输来的数据保存到本地文件中。 //// 收到 PUT300 命令,关闭当前传输文件。 //// 收到 PUT500 命令,TCP 文件传输过程结束,退出程序。 //// //// 文件传输服务端程序: //// sfd 在 accept() 后获取的新的客户端连接通道描述符 //// path 准备保存本地文件的路径信息 //// filename 根据接收报文中的文件名称与本地路径拼串而得到的返回文件信息 //// timeout 数据传输需要使用的延时参数 //// //// 返回数据: //// 0 ---- 文件接收成功 //// -2 -- 文件无法创建,打开文件名称失败 //// -1 -- 文件内容内容保存失败 //// //// 文件传输过程中,上传的文件名称有客户端提供,但是文件保存路径由服务器控制,以充分保证 //// 服务器文件系统的安全,避免服务器上的文件被客户端上传文件恶意覆盖。 //// //// ====================================================================================== ////int srv_mput_recvfile(int sfd,int timeout ){ int fd = -1; int blknum = 0,maxBlk = 0 ; char localfile[Nfile+1]; char tfile[Nfile+1],bfile[Nfile+1]; char *ptr; long fsize = 0; long start = time(NulL); int chkflg = 0; int fnum = 0; memset(tfile,sizeof(tfile)); while (1){ memset(&ncb,3)) { wLog(LOGERROR,2); chkflg = -3; } switch (Nstr_int(ncb.buff + 3,3)){ // 获取 PUT 后面的命令控制字,下面分析该控制字进行工作 case 100 : // 开始接收文件,打开本地文件 blknum = maxBlk = 0 ; wLog(LOGINFO,tfile); // 检查传输来文件名称中的路径信息,得到基本文件名称,将前面的路径 // 信息全部剔除,以保证本地文件的安全。当传输文件名称带有 ".." 标志 // 的时候,将会对服务器文件系统产生影响,需要保证该问题不会出现。 if( (ptr = strrchr(ncb.buff,':') ) != NulL ) maxBlk = atoi (ptr +1); // 从命令报文中得到文件传输块信息。 if( path ) sprintf(localfile,bfile); else strcpy(localfile,bfile ); // 与本地保存路径拼串,获得本地文件名称 fd = open(localfile,2); chkflg = -2; } fnum ++; // 对需要保存的本地文件,使用清空方式,创建新文件,既是该文件已经存在 // 也可以保证数据处理 wLog(LOGINFO,localfile ); break ; case 200 : // 保存文件内容 blknum ++; maxBlk --; if(blknum == 1 || !maxBlk )wLog(LOGINFO,2); chkflg = -1; } else fsize += ncb.wlen ; break ; case 300 : // 文件传输结束 if( !maxBlk ) wLog(LOGINFO,maxBlk ); close(fd); break ; case 500 : // 通信处理结束 chkflg = 1; break ; } memcpy(ncb.sndcmd,"成功接收[%d]文件,耗时 [%ld] 秒 ",time(NulL) - start ); return chkflg ;} // ================================================================================================== /////////////////////////////////////以下为客户端主动下载类程序///////////////////////////////////////////// ============================= 客户端使用 文件发送程序 ================================= ////// //// socket 方式文件发送程序,根据输入的 netinfo 建立通信通道,然后按照以下要求发送文件 //// GET100 发送文件下载请求,将远程文件名称和分块尺寸上送主机,等主机回应 //// GET200 接收文件内容,根据要求循环执行,...... //// GET300 数据发送结束 //// //// ======================================================================================= //// int cli_get_sendfile(char *netinfo,0666 ); if(fd == -1){ wLog(LOGERROR,strerror(errno) ); chkflg = -3; goto cli_get_sendfile_END; } fsize = sb.st_size; if(blockSize > 1024 * MAXKB ) blockSize = 1024 * MAXKB ; if(blockSize < 1024 ) blockSize = 1024; wLog(LOGINFO,sizeof (struct tcpBuffer)); ncb.wlen = snprintf(ncb.buff+25,0L,0 ); sprintf(ncb.sndcmd,"GET100fileINFO",strerror(errno) ); chkflg = -2; goto cli_get_sendfile_END; } wLog(LOGINFO,ncb.rcvcmd ); while (1){ blknum ++; memset(&ncb,"%06dGET200BLK%07d%1s%2s",strerror(errno) ); chkflg = -1; goto cli_get_sendfile_END; } if( blknum == 1 || blknum == maxBlk ) wLog(LOGINFO,strerror(errno) ); chkflg = -1; goto cli_get_sendfile_END; } } memset(&ncb,"GET300fileOVER",strerror(errno) ); chkflg = -1; goto cli_get_sendfile_END; } wLog(LOGINFO,time(NulL) - start ); cli_get_sendfile_END: if(sfd > 0) close(sfd); if(fd > 0) close(fd); // 关闭本文描述符和通信连接通道描述符 return chkflg;} // ============================ 服务端使用 文件传输程序 ================================= ////// //// socket 文件接收服务程序,对收到的通信报文进行分析。 //// 在收到 GET100 命令后,将该数据域中的文件名称与本地路径拼写得到完整的文件 //// 路径信息,打开本地文件。 //// 对 GET200 数据域传输来的数据保存到本地文件中。 //// 收到 GET300 命令,关闭本地文件,传输过程结束。 //// //// 文件传输服务端程序: //// sfd 在 accept() 后获取的新的客户端连接通道描述符 //// path 准备保存本地文件的路径信息 //// filename 根据接收报文中的文件名称与本地路径拼串而得到的返回文件信息 //// timeout 数据传输需要使用的延时参数 //// //// 返回数据: //// 0 ---- 文件接收成功 //// -2 -- 文件无法创建,打开文件名称失败 //// -1 -- 文件内容内容保存失败 //// ====================================================================================== ////int srv_get_recvfile(int sfd,"GET",3)){ // 获取 get 后面的命令控制字,下面分析该控制字进行工作 case 100 : // 开始接收文件,打开本地文件 wLog(LOGINFO,2); chkflg = -2; } // 对需要保存的本地文件,使用清空方式,创建新文件,既是该文件已经存在 // 也可以保证数据处理 wLog(LOGINFO,fsize ); return chkflg ;} // ============================= 客户端使用 多文件发送程序 =============================== ////// //// socket 方式文件发送程序,根据输入的 netinfo 建立通信通道,然后按照以下要求发送文件 //// GET100 发送文件基本信息 //// GET200 发送文件内容,根据要求循环执行,...... //// GET300 数据发送结束 //// //// ======================================================================================= //// //// 在建立好的文件传输通道上,将一个文件数据发送到服务端,传输后,不需要关闭传输通道。//int cli_mget_sendfile(int sfd,int timeout ){ int fd = -1; struct stat sb; int iRet ; int chkflg = 0 ; int maxBlk,blknum = 0; char *ftr; long start; long fsize; start = time(NulL); fd = open(localfile,ncb.rcvcmd ); while (1) { blknum ++; memset(&ncb,ncb.sndcmd ); iRet = tcp_readbuf(6,time(NulL) - start ); mSend_END: if(fd > 0) close(fd); // 关闭本文描述符和通信连接通道描述符 return chkflg; } // ============================================= 多文件处理函数 ====================================== //// //// //// 多文件发送服务程序,本程序对使用 ":" 分隔的文件信息自动进行分解,然后将每一个文件 //// 使用上述函数完成推送工作,在啊全部文件发送完毕后,程序将发出 get500 传输结束命令。 //// ///////////////////////////////////////////////////////////////////////////////////////////////////////////int cli_getm_sendfile(char *netinfo,int timeout){ int sfd = -1; int iRet ; int chkflg = 0 ; struct cli_getm_sendfile{ char lfile[Nfile+1]; // 本地文件名称 char rfile[Nfile+1]; // 远程文件名称 }mSnd; char *qList,*ptr ; char *ftr; int fnum = 0; long start ; start = time(NulL); sfd = make_tcpConnect (netinfo); // 使用 connect () 建立到服务器的连接通道 if(sfd < 0 ) { wLog(LOGERROR,':'); while(qList != NulL){ memset(&mSnd,ftr ? ftr + 1 : mSnd.lfile ); iRet = cli_mget_sendfile(sfd,':'); } // 对输入的文件名称进行分解,调用 cli_mget_sendfile() 函数进行数据发送。 memset(&ncb,sizeof (struct tcpBuffer )); ncb.wlen = snprintf (ncb.sndcmd,"get500FTPOVER","00" ); sprintf(ncb.buff,time(NulL) - start ); cli_get_sendfile_END: if(sfd > 0) close(sfd); // 关闭本文描述符和通信连接通道描述符 return chkflg;} // ============================ 服务端使用 多文件传输程序 =============================== ////// //// socket 文件接收服务程序,对收到的通信报文进行分析。 //// 在收到 GET100 命令后,将该数据域中的文件名称与本地路径拼写得到完整的文件 //// 路径信息,打开本地文件。 //// 对 GET200 数据域传输来的数据保存到本地文件中。 //// 收到 GET300 命令,关闭当前传输文件。 //// 收到 get500 命令,TCP 文件传输过程结束,退出程序。 //// //// 文件传输服务端程序: //// sfd 在 accept() 后获取的新的客户端连接通道描述符 //// path 准备保存本地文件的路径信息 //// filename 根据接收报文中的文件名称与本地路径拼串而得到的返回文件信息 //// timeout 数据传输需要使用的延时参数 //// //// 返回数据: //// 0 ---- 文件接收成功 //// -2 -- 文件无法创建,打开文件名称失败 //// -1 -- 文件内容内容保存失败 //// //// 文件传输过程中,上传的文件名称有客户端提供,但是文件保存路径由服务器控制,以充分保证 //// 服务器文件系统的安全,避免服务器上的文件被客户端上传文件恶意覆盖。 //// //// ====================================================================================== ////int srv_mget_recvfile(int sfd,19); if( memcmp(ncb.buff,"get",3) != 0 ) { wLog(LOGERROR,2); chkflg = -3; } switch ( Nstr_int(ncb.buff + 3,3) ) { // 获取 get 后面的命令控制字,下面分析该控制字进行工作 case 100 : // 开始接收文件,打开本地文件 blknum = maxBlk = 0 ; wLog(LOGINFO,2); chkflg = -2; } fnum ++; // 对需要保存的本地文件,使用清空方式,创建新文件,既是该文件已经存在 // 也可以保证数据处理 wLog(LOGINFO,time(NulL) - start ); return chkflg ;} #endif
以上就是本文的全部内容,希望对大家的学习有所帮助。
总结以上是内存溢出为你收集整理的C++文件上传、下载工具全部内容,希望文章能够帮你解决C++文件上传、下载工具所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)