C++文件上传、下载工具

本文实例为大家分享了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, 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]失败, faile [%d, %s]", temp, errno, 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, %s]", sLen, errno, strerror(errno) );

/* 数据没有处理完时,程序打印错误日志信息 */

return(sLen-left_bytes);

}

//

// 数据发送程序,在指定的延时内将指定长度的数据包发送到 sfd 上。

// 发送数据需要将报文长度保存在 sData 中,发送长度比实际的报文多出长度域 6字节

//

int tcp_writebuf(int sfd, char * sData, int sLen, int sTime)

{

int iRet = 0;

int left_bytes, thisWrite;

char *ptr = sData;

fd_set wfds;

struct timeval tv;

FD_ZERO(&wfds);

FD_SET(sfd, &wfds);

do{

iRet = select(sfd+1, NULL, &wfds, NULL, &tv) ;

}while (iRet < 0 && errno == EINTR );

if(iRet==0){

wLog(LOGERROR,"tcp_writebuf select 延时[%d] 结束, faile [%d, %s]", sTime, errno, strerror(errno) );

return -1;

}

// 检查通信链路的 写状态

left_bytes=sLen;

while(left_bytes >0 ){

if( (thisWrite = write(sfd, ptr, 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, %s]", left_bytes, errno, 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, %s]", netinfo , errno, strerror(errno) );

return -4;

}

wLog(LOGINFO, "成功建立到[%s]发送通道[%d]", netinfo, sfd );

fd = open(localFile, O_RDONLY);

if(fd == -1){

wLog(LOGERROR,"本地文件[%s]打开失败 error [%d, %s]", localFile , errno, strerror(errno) );

close (sfd );

return -3;

}

if (fstat(fd, &sb) < 0) {

wLog(LOGERROR,"取[%s]文件信息失败 error [%d, %s]", localFile , errno, 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] ", localFile, fsize );

maxBlk = (int ) ( (fsize ) / blockSize) ;

// 计算本文件的最大传输次数

if( fsize % blockSize ) maxBlk += 1;

// 不足整块的数据,需要按一块进行处理。

memset(&ncb , 0x00 , 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, %s]", ncb.wlen, remoteFile , errno, strerror(errno) );

chkflg = -2;

goto cli_put_sendFile_END;

}

wLog(LOGINFO,"发送报文头[%d] [%s]成功", ncb.wlen , 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]", remoteFile , errno, strerror(errno) );

chkflg = -2;

goto cli_put_sendFile_END;

}

wLog(LOGINFO,"接到返回数据 [%s]成功", ncb.rcvcmd );

// 循环将本地文件全部发送完毕

while ( 1 ){

blknum ++;

memset(&ncb , 0x00 , 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, "1", "00");

memcpy(ncb.buff, ncb.sndcmd , 25);

ncb.rlen += 25;

iRet = tcp_writebuf (sfd , ncb.buff, ncb.rlen, timeout);

if(iRet != ncb.rlen ){

wLog(LOGERROR,"发送 [%s] 失败 error [%d, %s]", ncb.sndcmd , errno, strerror(errno) );

chkflg = -1;

goto cli_put_sendFile_END;

}

if( blknum == 1 || blknum == maxBlk )

wLog(LOGINFO,"发送数据[%d] [%s]成功", ncb.rlen, ncb.sndcmd );

iRet = tcp_readbuf(6, sfd, ncb.rcvcmd , 19, timeout);

if(iRet != 19 || memcmp(ncb.rcvcmd+ 17, "00", 2)){

wLog(LOGERROR,"远程接收 [%s] 失败 error [%d, %s]", ncb.rcvcmd, errno, strerror(errno) );

chkflg = -1;

goto cli_put_sendFile_END;

}

}

memset(&ncb , 0x00 , sizeof (struct tcpBuffer ));

ncb.wlen = snprintf (ncb.sndcmd , sizeof (ncb.sndcmd )-1, "%-16s%1s%2s", "PUT300FILEOVER", "1", "00" );

sprintf(ncb.buff, "%06d%s", ncb.wlen, ncb.sndcmd );

iRet = tcp_writebuf (sfd , ncb.buff, ncb.wlen+6, timeout);

if(iRet != ncb.wlen + 6 ){

wLog(LOGERROR,"发送 FileOver 失败 error [%d, %s]", errno, strerror(errno) );

chkflg = -1;

goto cli_put_sendFile_END;

}

wLog(LOGINFO,"发送数据[%d] [%s]成功", iRet , ncb.sndcmd );

iRet = tcp_readbuf(6, sfd, ncb.rcvcmd , 19, timeout);

if(iRet != 19 || memcmp(ncb.rcvcmd+17, "00", 2)){

wLog(LOGERROR,"远程接收 FileOver 失败 error [%d, %s]", errno, strerror(errno) );

chkflg = -1;

goto cli_put_sendFile_END;

}

wLog(LOGINFO, "接到返回数据[%s]成功", ncb.rcvcmd );

wLog(LOGINFO, "传输[%s]-->[%s] [%d]块,共 [%ld]字节, 耗时 %ld 秒\n\n", localFile , remoteFile ,

blknum, fsize , 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, 0x00, sizeof(tfile));

while ( 1 ){

memset(&ncb, 0x00, sizeof (struct tcpBuffer));

ncb.rlen = tcp_readbuf (6, sfd, ncb.buff, sizeof(ncb.buff)-1, timeout);

if(ncb.rlen < 0 ) break ;

memcpy(ncb.sndcmd + 6, ncb.buff, 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, %s]", fileName , errno, strerror(errno) );

memcpy(ncb.rcvcmd+23, "01", 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.buff+19, ncb.rlen - 19);

if(ncb.wlen != ncb.rlen - 19 ) {

memcpy(ncb.sndcmd + 23, "01", 2);

chkflg = -1;

}

else fsize += ncb.wlen ;

break ;

case 300 : // 文件传输结束

if( !maxBlk )

wLog(LOGINFO, " 文件[%s]成功接收,共 [%d] 传输块 ", fileName, blknum );

else

wLog(LOGERROR,"文件[%s]接收结束,差错 [%d] 传输块 ", fileName , maxBlk );

close(fd);

chkflg = 1;

break ;

}

memcpy(ncb.sndcmd , "000019", 6);

ncb.sndcmd [22]='2';

ncb.wlen = tcp_writebuf (sfd , ncb.sndcmd , 25, timeout);

if(ncb.wlen != 25 ){

wLog(LOGERROR,"发送返回信息 [%s] 失败 error [%d, %s]", ncb.sndcmd + 6, errno, strerror(errno) );

}

if(chkflg ) break ;

}

if(fd) close (fd);

wLog(LOGINFO,"成功接收[%s]文件, 共 [%ld] 字节", fileName , fsize );

return chkflg ;

}

// ============================= 客户端使用 多文件发送程序 =============================== ////

// //

// socket 方式文件发送程序,根据输入的 netinfo 建立通信通道,然后按照以下要求发送文件 //

// PUT100 发送文件基本信息 //

// PUT200 发送文件内容,根据要求循环执行,...... //

// PUT300 数据发送结束 //

// //

// ======================================================================================= ////

//

// 在建立好的文件传输通道上,将一个文件数据发送到服务端,传输后,不需要关闭传输通道。

//

int cli_mput_sendFile(int sfd, char *localFile, char *remoteFile, int blockSize, 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, O_RDONLY);

if(fd == -1){

wLog(LOGERROR,"本地文件[%s]打开失败 error [%d, %s]", localFile , errno, strerror(errno) );

close (sfd );

return -3;

}

if (fstat(fd, &sb) < 0) {

wLog(LOGERROR,"取[%s]基本信息失败 error [%d, %s]", localFile , errno, 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, "成功打开本地文件[%s], size[%ld] ", localFile, fsize );

maxBlk = (int ) ( (fsize ) / blockSize) ;

// 计算本文件的最大传输次数

if( fsize % blockSize ) maxBlk += 1;

memset(&ncb , 0x00 , sizeof (struct tcpBuffer));

ftr = strrchr( remoteFile, '/');

ncb.wlen = snprintf(ncb.buff+25, sizeof(ncb.buff)-1, "%s:%010ld:%010d:%010d",

ftr ? ftr +1 : 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, %s]", ncb.wlen, remoteFile , errno, strerror(errno) );

chkflg = -2;

goto mSend_END;

}

wLog(LOGINFO,"发送报文头[%d] [%s]成功", ncb.wlen , 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]", remoteFile , errno, strerror(errno) );

chkflg = -2;

goto mSend_END;

}

wLog(LOGINFO,"接到返回数据 [%s]成功", ncb.rcvcmd );

while ( 1 ){

blknum ++;

memset(&ncb , 0x00 , 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, "1", "00");

memcpy(ncb.buff, ncb.sndcmd , 25);

ncb.rlen += 25;

iRet = tcp_writebuf (sfd , ncb.buff, ncb.rlen, timeout);

if(iRet != ncb.rlen ){

wLog(LOGERROR,"发送 [%s] 失败 error [%d, %s]", ncb.sndcmd , errno, strerror(errno) );

chkflg = -1;

goto mSend_END;

}

if( blknum == 1 || blknum == maxBlk )

wLog(LOGINFO,"发送数据[%d] [%s]成功", ncb.rlen, ncb.sndcmd );

iRet = tcp_readbuf(6, sfd, ncb.rcvcmd , 19, timeout);

if(iRet != 19 || memcmp(ncb.rcvcmd+ 17, "00", 2)){

wLog(LOGERROR,"远程接收 [%s] 失败 error [%d, %s]", ncb.rcvcmd, errno, strerror(errno) );

chkflg = -1;

goto mSend_END;

}

}

memset(&ncb , 0x00 , sizeof (struct tcpBuffer ));

ncb.wlen = snprintf (ncb.sndcmd , sizeof (ncb.sndcmd )-1, "%-16s%1s%2s", "PUT300FILEOVER", "1", "00" );

sprintf(ncb.buff, "%06d%s", ncb.wlen, ncb.sndcmd );

iRet = tcp_writebuf (sfd , ncb.buff, ncb.wlen+6, timeout);

if(iRet != ncb.wlen + 6 ){

wLog(LOGERROR,"发送 FileOver 失败 error [%d, %s]", errno, strerror(errno) );

chkflg = -1;

goto mSend_END;

}

wLog(LOGINFO,"发送数据[%d] [%s]成功", iRet , ncb.sndcmd );

iRet = tcp_readbuf(6, sfd, ncb.rcvcmd , 19, timeout);

if(iRet != 19 || memcmp(ncb.rcvcmd+17, "00", 2)){

wLog(LOGERROR,"远程接收 FileOver 失败 error [%d, %s]", errno, strerror(errno) );

chkflg = -1;

goto mSend_END;

}

wLog(LOGINFO, "接到返回数据[%s]成功", ncb.rcvcmd );

wLog(LOGINFO, "传输[%s]-->[%s] [%d]块,共 [%ld]字节, 耗时 %ld 秒\n\n", localFile , remoteFile ,

blknum, fsize , time(NULL) - start );

mSend_END:

if(fd > 0) close(fd);

// 关闭本文描述符和通信连接通道描述符

return chkflg;

}

// ============================================= 多文件处理函数 ====================================== //

// //

// //

// 多文件发送服务程序,本程序对使用 ":" 分隔的文件信息自动进行分解,然后将每一个文件 //

// 使用上述函数完成推送工作,在啊全部文件发送完毕后,程序将发出 PUT500 传输结束命令。 //

// //

/////////////////////////////////////////////////////////////////////////////////////////////////////////

int cli_putm_sendFile(char *netinfo, char *sLocalFile, int blockSize, 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, %s]", netinfo , errno, strerror(errno) );

return -4;

}

wLog(LOGINFO, "成功建立到[%s]发送通道[%d]", netinfo, sfd );

qlist = sLocalFile;

ptr = strchr(qlist, ':');

while(qlist != NULL)

{

memset(&mSnd, 0x00, 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, blockSize, timeout );

if( iRet == 0 ) fnum ++ ;

qlist = ptr + 1;

ptr = strchr(qlist, ':');

}

// 对输入的文件名称进行分解,调用 cli_mput_sendFile() 函数进行数据发送。

memset(&ncb , 0x00 , sizeof (struct tcpBuffer ));

ncb.wlen = snprintf (ncb.sndcmd , sizeof (ncb.sndcmd )-1, "%-16s%1s%2s", "PUT500FTPOVER", "1", "00" );

sprintf(ncb.buff, "%06d%s", ncb.wlen, ncb.sndcmd );

iRet = tcp_writebuf (sfd , ncb.buff, ncb.wlen+6, timeout);

if(iRet != ncb.wlen + 6 )

{

wLog(LOGERROR,"发送 FileOver 失败 error [%d, %s]", errno, strerror(errno) );

chkflg = -1;

goto cli_put_sendFile_END;

}

wLog(LOGINFO,"发送数据[%d] [%s]成功", iRet , ncb.sndcmd );

iRet = tcp_readbuf(6, sfd, ncb.rcvcmd , 19, timeout);

if(iRet != 19 || memcmp(ncb.rcvcmd+17, "00", 2))

{

wLog(LOGERROR,"远程接收 FileOver 失败 error [%d, %s]", errno, strerror(errno) );

chkflg = -1;

goto cli_put_sendFile_END;

}

wLog(LOGINFO, "接到返回数据[%s]成功", ncb.rcvcmd );

wLog(LOGINFO, "共 [%d]个文件, 耗时 %ld 秒\n\n", 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 , char *path, 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, 0x00, sizeof(tfile));

while (1){

memset(&ncb, 0x00, sizeof (struct tcpBuffer));

ncb.rlen = tcp_readbuf (6, sfd, ncb.buff, sizeof(ncb.buff)-1, timeout);

if(ncb.rlen < 0 ) break ;

memcpy(ncb.sndcmd + 6, ncb.buff, 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 : // 开始接收文件,打开本地文件

blknum = maxBlk = 0 ;

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(localFile, "%s/%s", path, bfile);

else strcpy(localFile, bfile );

// 与本地保存路径拼串,获得本地文件名称

fd = open(localFile, O_CREAT|O_WRONLY|O_TRUNC, 0666 );

if(fd < 0 ) {

wLog(LOGERROR,"生成本地文件 [%s] 失败 error [%d, %s]", localFile , errno, strerror(errno) );

memcpy(ncb.rcvcmd+23, "01", 2);

chkflg = -2;

}

fnum ++;

// 对需要保存的本地文件,使用清空方式,创建新文件,既是该文件已经存在

// 也可以保证数据处理

wLog(LOGINFO,"创建本地文件[%s]成功", localFile );

break ;

case 200 : // 保存文件内容

blknum ++;

maxBlk --;

if(blknum == 1 || !maxBlk )wLog(LOGINFO, "接收数据[%s]成功", ncb.sndcmd+6 );

ncb.wlen = write(fd, ncb.buff+19, ncb.rlen - 19);

if(ncb.wlen != ncb.rlen - 19 ) {

memcpy(ncb.sndcmd + 23, "01", 2);

chkflg = -1;

}

else fsize += ncb.wlen ;

break ;

case 300 : // 文件传输结束

if( !maxBlk )

wLog(LOGINFO, " 文件[%s]成功接收,共 [%d] 传输块 ", localFile, blknum );

else

wLog(LOGERROR,"文件[%s]接收结束,差错 [%d] 传输块 ", localFile , maxBlk );

close(fd);

break ;

case 500 : // 通信处理结束

chkflg = 1;

break ;

}

memcpy(ncb.sndcmd , "000019", 6);

ncb.sndcmd [22]='2';

ncb.wlen = tcp_writebuf (sfd , ncb.sndcmd , 25, timeout);

if(ncb.wlen != 25 ){

wLog(LOGERROR,"发送返回信息 [%s] 失败 error [%d, %s]", ncb.sndcmd + 6, errno, strerror(errno) );

}

if(chkflg ) break ;

}

if(fd) close (fd);

wLog(LOGINFO, "成功接收[%d]文件, 耗时 [%ld] 秒 ", fnum , time(NULL) - start );

return chkflg ;

}

// ================================================================================================== //

///////////////////////////////////以下为客户端主动下载类程序///////////////////////////////////////////

// ============================= 客户端使用 文件发送程序 ================================= ////

// //

// socket 方式文件发送程序,根据输入的 netinfo 建立通信通道,然后按照以下要求发送文件 //

// GET100 发送文件下载请求,将远程文件名称和分块尺寸上送主机,等主机回应 //

// GET200 接收文件内容,根据要求循环执行,...... //

// GET300 数据发送结束 //

// //

// ======================================================================================= ////

int cli_get_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, %s]", netinfo , errno, strerror(errno) );

return -4;

}

wLog(LOGINFO, "成功建立到[%s]发送通道[%d]", netinfo, sfd );

fd = open(localFile, O_CREAT|O_WRONLY|O_TRUNC, 0666 );

if(fd == -1){

wLog(LOGERROR,"本地文件[%s]打开失败 error [%d, %s]", localFile , errno, strerror(errno) );

close (sfd );

return -3;

}

if (fstat(fd, &sb) < 0) {

wLog(LOGERROR,"取[%s]文件信息失败 error [%d, %s]", localFile , errno, 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, "成功打开本地文件[%s], size[%ld] ", localFile, fsize );

maxBlk = (int ) ( (fsize ) / blockSize) ;

// 计算本文件的最大传输次数

if( fsize % blockSize ) maxBlk += 1;

// 不足整块的数据,需要按一块进行处理。

memset(&ncb , 0x00 , sizeof (struct tcpBuffer));

ncb.wlen = snprintf(ncb.buff+25, sizeof(ncb.buff)-1, "%s:%010ld:%010d:%010d",

remoteFile, 0L , blockSize , 0 );

sprintf(ncb.sndcmd , "%06d%-16s%1s%2s", ncb.wlen+19, "GET100FILEINFO", "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, %s]", ncb.wlen, remoteFile , errno, strerror(errno) );

chkflg = -2;

goto cli_get_sendFile_END;

}

wLog(LOGINFO, "发送报文头[%d] [%s]成功", ncb.wlen , 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]", remoteFile , errno, strerror(errno) );

chkflg = -2;

goto cli_get_sendFile_END;

}

wLog(LOGINFO,"接到返回数据 [%s]成功", ncb.rcvcmd );

while (1){

blknum ++;

memset(&ncb , 0x00 , sizeof (struct tcpBuffer ));

ncb.rlen = read (fd, ncb.buff+25, blockSize );

if(ncb.rlen < 1 ) break ; // 本地文件已经发送结束

sprintf (ncb.sndcmd , "%06dGET200BLK%07d%1s%2s", ncb.rlen+19, blknum, "1", "00");

memcpy(ncb.buff, ncb.sndcmd , 25);

ncb.rlen += 25;

iRet = tcp_writebuf (sfd , ncb.buff, ncb.rlen, timeout);

if(iRet != ncb.rlen ){

wLog(LOGERROR,"发送 [%s] 失败 error [%d, %s]", ncb.sndcmd , errno, strerror(errno) );

chkflg = -1;

goto cli_get_sendFile_END;

}

if( blknum == 1 || blknum == maxBlk )

wLog(LOGINFO, "发送数据[%d] [%s]成功", ncb.rlen, ncb.sndcmd );

iRet = tcp_readbuf(6, sfd, ncb.rcvcmd , 19, timeout);

if(iRet != 19 || memcmp(ncb.rcvcmd+ 17, "00", 2)){

wLog(LOGERROR,"远程接收 [%s] 失败 error [%d, %s]", ncb.rcvcmd, errno, strerror(errno) );

chkflg = -1;

goto cli_get_sendFile_END;

}

}

memset(&ncb , 0x00 , sizeof (struct tcpBuffer ));

ncb.wlen = snprintf (ncb.sndcmd , sizeof (ncb.sndcmd )-1, "%-16s%1s%2s", "GET300FILEOVER", "1", "00" );

sprintf(ncb.buff, "%06d%s", ncb.wlen, ncb.sndcmd );

iRet = tcp_writebuf (sfd , ncb.buff, ncb.wlen+6, timeout);

if(iRet != ncb.wlen + 6 ){

wLog(LOGERROR,"发送 FileOver 失败 error [%d, %s]", errno, strerror(errno) );

chkflg = -1;

goto cli_get_sendFile_END;

}

wLog(LOGINFO, "发送数据[%d] [%s]成功", iRet , ncb.sndcmd );

iRet = tcp_readbuf(6, sfd, ncb.rcvcmd , 19, timeout);

if(iRet != 19 || memcmp(ncb.rcvcmd+17, "00", 2)){

wLog(LOGERROR,"远程接收 FileOver 失败 error [%d, %s]", errno, strerror(errno) );

chkflg = -1;

goto cli_get_sendFile_END;

}

wLog(LOGINFO, "接到返回数据[%s]成功", ncb.rcvcmd );

wLog(LOGINFO, "传输[%s]-->[%s] [%d]块,共 [%ld]字节, 耗时 %ld 秒\n\n", localFile , remoteFile ,

blknum, fsize , 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 , 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, 0x00, sizeof(tfile));

while (1){

memset(&ncb, 0x00, sizeof (struct tcpBuffer));

ncb.rlen = tcp_readbuf (6, sfd, ncb.buff, sizeof(ncb.buff)-1, timeout);

if(ncb.rlen < 0 ) break ;

memcpy(ncb.sndcmd + 6, ncb.buff, 19);

if(memcmp(ncb.buff, "GET", 3) ) {

wLog(LOGERROR,"接收命令序列 [%s] 错误 ,程序退出. ", ncb.sndcmd+6 );

memcpy(ncb.rcvcmd+23, "01", 2);

chkflg = -3;

}

switch (Nstr_int(ncb.buff + 3, 3)){

// 获取 get 后面的命令控制字,下面分析该控制字进行工作

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, %s]", fileName , errno, strerror(errno) );

memcpy(ncb.rcvcmd+23, "01", 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.buff+19, ncb.rlen - 19);

if(ncb.wlen != ncb.rlen - 19 ) {

memcpy(ncb.sndcmd + 23, "01", 2);

chkflg = -1;

}

else fsize += ncb.wlen ;

break ;

case 300 : // 文件传输结束

if( !maxBlk )

wLog(LOGINFO, " 文件[%s]成功接收,共 [%d] 传输块 ", fileName, blknum );

else

wLog(LOGERROR,"文件[%s]接收结束,差错 [%d] 传输块 ", fileName , maxBlk );

close(fd);

chkflg = 1;

break ;

}

memcpy(ncb.sndcmd , "000019", 6);

ncb.sndcmd [22]='2';

ncb.wlen = tcp_writebuf (sfd , ncb.sndcmd , 25, timeout);

if(ncb.wlen != 25 ){

wLog(LOGERROR,"发送返回信息 [%s] 失败 error [%d, %s]", ncb.sndcmd + 6, errno, strerror(errno) );

}

if(chkflg ) break ;

}

if(fd) close (fd);

wLog(LOGINFO, "成功接收[%s]文件, 共 [%ld] 字节", fileName , fsize );

return chkflg ;

}

// ============================= 客户端使用 多文件发送程序 =============================== ////

// //

// socket 方式文件发送程序,根据输入的 netinfo 建立通信通道,然后按照以下要求发送文件 //

// GET100 发送文件基本信息 //

// GET200 发送文件内容,根据要求循环执行,...... //

// GET300 数据发送结束 //

// //

// ======================================================================================= ////

//

// 在建立好的文件传输通道上,将一个文件数据发送到服务端,传输后,不需要关闭传输通道。

//

int cli_mget_sendFile(int sfd, char *localFile, char *remoteFile, int blockSize, 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, O_RDONLY);

if(fd == -1){

wLog(LOGERROR,"本地文件[%s]打开失败 error [%d, %s]", localFile , errno, strerror(errno) );

close (sfd );

return -3;

}

if (fstat(fd, &sb) < 0) {

wLog(LOGERROR,"取[%s]基本信息失败 error [%d, %s]", localFile , errno, 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,"成功打开本地文件[%s], size[%ld] ", localFile, fsize );

maxBlk = (int ) ( (fsize ) / blockSize) ;

// 计算本文件的最大传输次数

if( fsize % blockSize ) maxBlk += 1;

memset(&ncb , 0x00 , sizeof (struct tcpBuffer));

ftr = strrchr( remoteFile, '/');

ncb.wlen = snprintf(ncb.buff+25, sizeof(ncb.buff)-1, "%s:%010ld:%010d:%010d",

ftr ? ftr +1 : remoteFile, fsize , blockSize , maxBlk );

sprintf(ncb.sndcmd , "%06d%-16s%1s%2s", ncb.wlen+19, "GET100FILEINFO", "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, %s]", ncb.wlen, remoteFile , errno, strerror(errno) );

chkflg = -2;

goto mSend_END;

}

wLog(LOGINFO,"发送报文头[%d] [%s]成功", ncb.wlen , 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]", remoteFile , errno, strerror(errno) );

chkflg = -2;

goto mSend_END;

}

wLog(LOGINFO,"接到返回数据 [%s]成功", ncb.rcvcmd );

while (1)

{

blknum ++;

memset(&ncb , 0x00 , sizeof (struct tcpBuffer ));

ncb.rlen = read (fd, ncb.buff+25, blockSize );

if(ncb.rlen < 1 ) break ; // 本地文件已经发送结束

sprintf (ncb.sndcmd , "%06dGET200BLK%07d%1s%2s", ncb.rlen+19, blknum, "1", "00");

memcpy(ncb.buff, ncb.sndcmd , 25);

ncb.rlen += 25;

iRet = tcp_writebuf (sfd , ncb.buff, ncb.rlen, timeout);

if(iRet != ncb.rlen ){

wLog(LOGERROR,"发送 [%s] 失败 error [%d, %s]", ncb.sndcmd , errno, strerror(errno) );

chkflg = -1;

goto mSend_END;

}

if( blknum == 1 || blknum == maxBlk )

wLog(LOGINFO,"发送数据[%d] [%s]成功", ncb.rlen, ncb.sndcmd );

iRet = tcp_readbuf(6, sfd, ncb.rcvcmd , 19, timeout);

if(iRet != 19 || memcmp(ncb.rcvcmd+ 17, "00", 2)){

wLog(LOGERROR,"远程接收 [%s] 失败 error [%d, %s]", ncb.rcvcmd, errno, strerror(errno) );

chkflg = -1;

goto mSend_END;

}

}

memset(&ncb , 0x00 , sizeof (struct tcpBuffer ));

ncb.wlen = snprintf (ncb.sndcmd , sizeof (ncb.sndcmd )-1, "%-16s%1s%2s", "GET300FILEOVER", "1", "00" );

sprintf(ncb.buff, "%06d%s", ncb.wlen, ncb.sndcmd );

iRet = tcp_writebuf (sfd , ncb.buff, ncb.wlen+6, timeout);

if(iRet != ncb.wlen + 6 ){

wLog(LOGERROR,"发送 FileOver 失败 error [%d, %s]", errno, strerror(errno) );

chkflg = -1;

goto mSend_END;

}

wLog(LOGINFO,"发送数据[%d] [%s]成功", iRet , ncb.sndcmd );

iRet = tcp_readbuf(6, sfd, ncb.rcvcmd , 19, timeout);

if(iRet != 19 || memcmp(ncb.rcvcmd+17, "00", 2)){

wLog(LOGERROR,"远程接收 FileOver 失败 error [%d, %s]", errno, strerror(errno) );

chkflg = -1;

goto mSend_END;

}

wLog(LOGINFO, "接到返回数据[%s]成功", ncb.rcvcmd );

wLog(LOGINFO, "传输[%s]-->[%s] [%d]块,共 [%ld]字节, 耗时 %ld 秒\n\n", localFile , remoteFile ,

blknum, fsize , time(NULL) - start );

mSend_END:

if(fd > 0) close(fd);

// 关闭本文描述符和通信连接通道描述符

return chkflg;

}

// ============================================= 多文件处理函数 ====================================== //

// //

// //

// 多文件发送服务程序,本程序对使用 ":" 分隔的文件信息自动进行分解,然后将每一个文件 //

// 使用上述函数完成推送工作,在啊全部文件发送完毕后,程序将发出 get500 传输结束命令。 //

// //

/////////////////////////////////////////////////////////////////////////////////////////////////////////

int cli_getm_sendFile(char *netinfo, char *sLocalFile, int blockSize, 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,"建立到[%s]文件传输通道失败 error [%d, %s]", netinfo , errno, strerror(errno) );

return -4;

}

wLog(LOGINFO, "成功建立到[%s]发送通道[%d]", netinfo, sfd );

qlist = sLocalFile;

ptr = strchr(qlist, ':');

while(qlist != NULL){

memset(&mSnd, 0x00, sizeof(mSnd));

strncpy(mSnd.lFile , qlist, ptr - qlist);

ftr = strrchr(mSnd.lFile, '/');

strcpy(mSnd.rFile , ftr ? ftr + 1 : mSnd.lFile );

iRet = cli_mget_sendFile(sfd, mSnd.lFile, mSnd.rFile, blockSize, timeout );

if( iRet == 0 ) fnum ++ ;

qlist = ptr + 1;

ptr = strchr(qlist, ':');

}

// 对输入的文件名称进行分解,调用 cli_mget_sendFile() 函数进行数据发送。

memset(&ncb , 0x00 , sizeof (struct tcpBuffer ));

ncb.wlen = snprintf (ncb.sndcmd , sizeof (ncb.sndcmd )-1, "%-16s%1s%2s", "get500FTPOVER", "1", "00" );

sprintf(ncb.buff, "%06d%s", ncb.wlen, ncb.sndcmd );

iRet = tcp_writebuf (sfd , ncb.buff, ncb.wlen+6, timeout);

if(iRet != ncb.wlen + 6 ){

wLog(LOGERROR,"发送 FileOver 失败 error [%d, %s]", errno, strerror(errno) );

chkflg = -1;

goto cli_get_sendFile_END;

}

wLog(LOGINFO, "发送数据[%d] [%s]成功", iRet , ncb.sndcmd );

iRet = tcp_readbuf(6, sfd, ncb.rcvcmd , 19, timeout);

if(iRet != 19 || memcmp(ncb.rcvcmd+17, "00", 2)){

wLog(LOGERROR,"远程接收 FileOver 失败 error [%d, %s]", errno, strerror(errno) );

chkflg = -1;

goto cli_get_sendFile_END;

}

wLog(LOGINFO, "接到返回数据[%s]成功", ncb.rcvcmd );

wLog(LOGINFO, "共 [%d]个文件, 耗时 %ld 秒\n\n", fnum , 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 , char *path, 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, 0x00, sizeof(tfile));

while (1){

memset(&ncb, 0x00, sizeof (struct tcpBuffer));

ncb.rlen = tcp_readbuf (6, sfd, ncb.buff, sizeof(ncb.buff)-1, timeout);

if(ncb.rlen < 0 ) break ;

memcpy(ncb.sndcmd + 6, ncb.buff, 19);

if( memcmp(ncb.buff, "get", 3) != 0 ) {

wLog(LOGERROR,"接收命令序列 [%s] 错误 ,程序退出. ", ncb.sndcmd+6 );

memcpy(ncb.rcvcmd+23, "01", 2);

chkflg = -3;

}

switch ( Nstr_int(ncb.buff + 3, 3) )

{

// 获取 get 后面的命令控制字,下面分析该控制字进行工作

case 100 : // 开始接收文件,打开本地文件

blknum = maxBlk = 0 ;

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(localFile, "%s/%s", path, bfile);

else strcpy(localFile, bfile );

// 与本地保存路径拼串,获得本地文件名称

fd = open(localFile, O_CREAT|O_WRONLY|O_TRUNC, 0666 );

if(fd < 0 ) {

wLog(LOGERROR,"生成本地文件 [%s] 失败 error [%d, %s]", localFile , errno, strerror(errno) );

memcpy(ncb.rcvcmd+23, "01", 2);

chkflg = -2;

}

fnum ++;

// 对需要保存的本地文件,使用清空方式,创建新文件,既是该文件已经存在

// 也可以保证数据处理

wLog(LOGINFO, "创建本地文件[%s]成功", localFile );

break ;

case 200 : // 保存文件内容

blknum ++;

maxBlk --;

if(blknum == 1 || !maxBlk )wLog(LOGINFO, "接收数据[%s]成功", ncb.sndcmd+6 );

ncb.wlen = write(fd, ncb.buff+19, ncb.rlen - 19);

if(ncb.wlen != ncb.rlen - 19 ) {

memcpy(ncb.sndcmd + 23, "01", 2);

chkflg = -1;

}

else fsize += ncb.wlen ;

break ;

case 300 : // 文件传输结束

if( !maxBlk )

wLog(LOGINFO, " 文件[%s]成功接收,共 [%d] 传输块 ", localFile, blknum );

else

wLog(LOGERROR,"文件[%s]接收结束,差错 [%d] 传输块 ", localFile , maxBlk );

close(fd);

break ;

case 500 : // 通信处理结束

chkflg = 1;

break ;

}

memcpy(ncb.sndcmd , "000019", 6);

ncb.sndcmd [22]='2';

ncb.wlen = tcp_writebuf (sfd , ncb.sndcmd , 25, timeout);

if(ncb.wlen != 25 ){

wLog(LOGERROR,"发送返回信息 [%s] 失败 error [%d, %s]", ncb.sndcmd + 6, errno, strerror(errno) );

}

if(chkflg ) break ;

}

if(fd) close (fd);

wLog(LOGINFO, "成功接收[%d]文件, 耗时 [%ld] 秒 ", fnum , time(NULL) - start );

return chkflg ;

}

#endif

以上是 C++文件上传、下载工具 的全部内容, 来源链接: utcz.com/z/330048.html

回到顶部