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

以上就是本文的全部内容,希望对大家的学习有所帮助。

(0)

相关推荐

  • Java FTPClient实现文件上传下载

    在JAVA程序中,经常需要和FTP打交道,比如向FTP服务器上传文件.下载文件,本文简单介绍如何利用jakarta commons中的FTPClient(在commons-net包中)实现上传下载文件. 所用到的jar包有:  commons-net-1.4.1.jar  jakarta-oro.jar  一.上传文件 文件上传源代码 /** * Description: 向FTP服务器上传文件 * @Version1.0 * @param url FTP服务器hostname * @param

  • JAVA使用commos-fileupload实现文件上传与下载实例解析

    首先给大家介绍一文件的上传 实体类 import java.sql.Timestamp; /** * * @Decription 文件上传实体类 * */ public class Upfile { private String id;// ID主键 使用uuid随机生成 private String uuidname; // UUID名称 private String filename;//文件名称 private String savepath; // 保存路径 private Timest

  • JavaWeb实现文件上传下载功能实例解析

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上传文件的输入流然后再解析里面的请求参数是比较麻烦,所以一般选择采用apache的开源工具common-fileupload这个文件上传组件.这个common-fileupload上传组件的jar包可以去apache官网上面下载,也可以在struts的lib文件夹下面找到,stru

  • asp.net 多文件上传,兼容IE6/7/8,提供完整代码下载

    最终效果如下:现贴出核心代码如下: aspx里的代码: 复制代码 代码如下: <div style="text-align: center"> <div style="width: 200px;"> <input type="file" size="50" name="File" /> <span id="upload"></span

  • 使用pcs api往免费的百度网盘上传下载文件的方法

    百度个人云盘空间大,完全免费,而且提供了pcs api供调用操作文件,在平时的项目里往里面保存一些文件是很实用的. 环境准备: 开通读写网盘的权限及获取access_token:http://blog.csdn.net/langyuezhang/article/details/47206621 百度官方pcs api文档:http://developer.baidu.com/wiki/index.php?title=docs/pcs/overview,上面有各种语言的SDK,我用的laravel

  • Asp.net实现MVC处理文件的上传下载功能实例教程

    上传于下载功能是程序设计中非常常见的一个功能,在ASP.NET程序开发中有着非常广泛的应用.本文就以实例形式来实现这一功能. 一.概述 如果你仅仅只有Asp.net Web Forms背景转而学习Asp.net MVC的,我想你的第一个经历或许是那些曾经让你的编程变得愉悦无比的服务端控件都驾鹤西去了.FileUpload就是其中一个,而这个控件的缺席给我们带来一些小问题.这篇文章主要说如何在Asp.net MVC中上传文件,然后如何再从服务器中把上传过的文件下载下来. 二.实现方法 1.文件上传

  • asp.net Web Services上传和下载文件(完整代码)第1/2页

    下面,我们就分别介绍如何通过Web Services从服务器下载文件到客户端和从客户端通过Web Services上载文件到服务器.一:通过Web Services显示和下载文件 我们这里建立的Web Services的名称为GetBinaryFile,提供两个公共方法:分别是GetImage()和GetImageType(),前者返回二进制文件字节数组,后者返回文件类型,其中,GetImage()方法有一个参数,用来在客户端选择要显示或下载的文件名字.这里我们所显示和下载的文件可以不在虚拟目录

  • Jsp页面实现文件上传下载类代码第1/2页

    刚才和lp看完电影,把jsp页面抽出class调整了一下.最近总上经典,是感觉既然当了斑竹,就该留下点什么.lp这几天也半开玩笑半生气的说,一回来就上经典,就发帖,你干脆娶经典作lp得了.想想,这几天是有点夸张,以后放慢速度了.保持1星期1帖吧,那样也能多想写,多总结些.发帖的初衷就是有时候看到有的朋友问的问题,似乎还没有走进java的门,希望这样的帖子,能对新手一点帮助,也就满足了.有时候随意的一段话,其实也是自己的一点经验,而有时候之所以絮絮叨叨,是想把问题说的清楚明白,让高手见笑了.因为在

  • 用asp实现文件浏览、上传、下载的程序

    可以放在服务器上,对服务器上的文件进行浏览.上传.下载,可下载文件源码. 把下所有代码入在一个文件里即可,文件的后缀要为asp. 复制代码 代码如下: <%  thedir = request("thedir")  if thedir = "" then   folderini = server.mappath(".")&"\"  else   folderini = server.mappath(thedir)

  • Flex与.NET互操作 使用FileReference+HttpHandler实现文件上传/下载

    在Flex的应用开发中,同ASP.NET,JSP,PHP等应用一样,都会有上传/下载文件的应用需求,Flex的SDK也为我们提供了专门的类 FileRefUdderence实现文件上传/下载.Flex只是作为一个客户端,要实现上传或下载必须得为其提供一个服务端来接受上传或下载的请求,本文以ASP.NET中的HttpHandler作为文件上传的服务端来完成上传功能. OK,我们从Flex客户端开始,看看客户端是通过什么方式想服务端发起请求.Flex客户端要完成文件上传下载都是通过FileRefUd

随机推荐