欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++文件上傳、下載工具

 更新時間:2016年05月15日 14:59:42   作者:逍遙天下1688  
這篇文章主要為大家詳細介紹了C++文件上傳、下載工具的相關(guān)資料,感興趣的小伙伴們可以參考一下

本文實例為大家分享了C++文件上傳下載的實現(xiàn)代碼,供大家參考,具體內(nèi)容如下

#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 通信命令行緩沖區(qū)
typedef struct tcpCmd {
  int  len;      // 命令行長度
  char cmd[NCMD+1];  // 命令行緩沖區(qū)
} tcpCmd;
 
struct tcpBuffer {
 
  int rlen;      // 接收數(shù)據(jù)長度
  int wlen;      // 發(fā)送數(shù)據(jù)長度
 
  char rcvcmd[NCMD+1];  // 接收命令域數(shù)據(jù)
  char sndcmd[NCMD+1];  // 接收命令域數(shù)據(jù)
 
  tcpCmd rCmd    ;  // 接收緩沖區(qū)
  tcpCmd sCmd    ;  // 發(fā)送緩沖區(qū)
 
  char buff[1024 * MAXKB + 64 + 1 ];  // 報文緩沖區(qū), 包含命令控制串和實際報文數(shù)據(jù)
 
} ncb;
 
 
 
// ////////////////////////////////////////////////////////////////////////////////////////////// ////
//                                                //
// 根據(jù)報文頭數(shù)據(jù)要求,接收一個通信數(shù)據(jù)。                            //
// 程序首先按照要求讀取 headlen 長度的長度包數(shù)據(jù),然后再次從網(wǎng)絡(luò)上讀取真正長度的數(shù)據(jù)包。     //
//                                                //
// 數(shù)據(jù)接收函數(shù)分兩次進行處理,返回數(shù)據(jù) sData 中已經(jīng)不再包含 6位通信長度數(shù)據(jù)。          //
// ///////////////////////////////////////////////////////////////////////////////////////////// ////
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] 結(jié)束, 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]錯誤,數(shù)據(jù)非法. ", 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) );
  /* 數(shù)據(jù)沒有處理完時,程序打印錯誤日志信息 */
 
  return(sLen-left_bytes);
}
 
//
// 數(shù)據(jù)發(fā)送程序,在指定的延時內(nèi)將指定長度的數(shù)據(jù)包發(fā)送到 sfd 上。
// 發(fā)送數(shù)據(jù)需要將報文長度保存在 sData 中,發(fā)送長度比實際的報文多出長度域 6字節(jié)
//
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] 結(jié)束, faile [%d, %s]", sTime, errno, strerror(errno) );
    return -1;
  }
  // 檢查通信鏈路的 寫狀態(tài)
 
  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;
  }
  // 將數(shù)據(jù)發(fā)送到通信端口
 
  if(left_bytes && ptr != sData )
    wLog(LOGERROR,"[tcp_sendbuf left_bytes[%d] faile [%d, %s]", left_bytes, errno, strerror(errno) );
  return(sLen-left_bytes);
}
 
//  ============================= 客戶端使用 文件發(fā)送程序 ================================= ////
//                                              //
//  socket 方式文件發(fā)送程序,根據(jù)輸入的 netinfo 建立通信通道,然后按照以下要求發(fā)送文件   //
//  PUT100 發(fā)送文件基本信息                                 //
//  PUT200 發(fā)送文件內(nèi)容,根據(jù)要求循環(huán)執(zhí)行,......                      //
//  PUT300 數(shù)據(jù)發(fā)送結(jié)束                                   //
//                                              //
//  ======================================================================================= ////
 
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 () 建立到服務(wù)器的連接通道
 
  if(sfd < 0 ) {
    wLog(LOGERROR,"建立到[%s]連接失敗 error [%d, %s]", netinfo , errno, strerror(errno) );
    return -4;
  }
  wLog(LOGINFO, "成功建立到[%s]發(fā)送通道[%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) ;
  // 計算本文件的最大傳輸次數(shù)
  if( fsize % blockSize ) maxBlk += 1;
  // 不足整塊的數(shù)據(jù),需要按一塊進行處理。
 
  memset(&ncb , 0x00 , sizeof (struct tcpBuffer));
 
  // 準備發(fā)送文件控制命令串, 告訴對方準備發(fā)送文件的基礎(chǔ)信息
  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,"發(fā)送[%d] [%s]失敗 error [%d, %s]", ncb.wlen, remoteFile , errno, strerror(errno) );
    chkflg = -2;
    goto cli_put_sendFile_END;
  }
  wLog(LOGINFO,"發(fā)送報文頭[%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,"接到返回數(shù)據(jù) [%s]成功", ncb.rcvcmd );
 
 
  // 循環(huán)將本地文件全部發(fā)送完畢
  while ( 1 ){
    blknum ++;
    memset(&ncb , 0x00 , sizeof (struct tcpBuffer ));
    ncb.rlen = read (fd, ncb.buff+25, blockSize );
    if(ncb.rlen < 1 ) break ; // 本地文件已經(jīng)發(fā)送結(jié)束
 
    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,"發(fā)送 [%s] 失敗 error [%d, %s]", ncb.sndcmd , errno, strerror(errno) );
      chkflg = -1;
      goto cli_put_sendFile_END;
    }
    if( blknum == 1 || blknum == maxBlk )
      wLog(LOGINFO,"發(fā)送數(shù)據(jù)[%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,"發(fā)送 FileOver 失敗 error [%d, %s]", errno, strerror(errno) );
    chkflg = -1;
    goto cli_put_sendFile_END;
  }
  wLog(LOGINFO,"發(fā)送數(shù)據(jù)[%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, "接到返回數(shù)據(jù)[%s]成功", ncb.rcvcmd );
 
  wLog(LOGINFO, "傳輸[%s]-->[%s] [%d]塊,共 [%ld]字節(jié), 耗時 %ld 秒\n\n", localFile , remoteFile ,
      blknum, fsize , time(NULL) - start );
 
 
cli_put_sendFile_END:
 
  if(sfd > 0) close(sfd);
  if(fd > 0) close(fd);
  // 關(guān)閉本文描述符和通信連接通道描述符
 
  return chkflg;
}
 
 
//  ============================ 服務(wù)端使用 文件傳輸程序 ================================= ////
//                                             //
//  socket 文件接收服務(wù)程序,對收到的通信報文進行分析。                  //
//  在收到 PUT100 命令后,將該數(shù)據(jù)域中的文件名稱與本地路徑拼寫得到完整的文件        //
//         路徑信息,打開本地文件。                         //
//  對 PUT200 數(shù)據(jù)域傳輸來的數(shù)據(jù)保存到本地文件中。                     //
//  收到 PUT300 命令,關(guān)閉本地文件,傳輸過程結(jié)束。                     //
//                                             //
//  文件傳輸服務(wù)端程序:                                  //
//  sfd  在 accept() 后獲取的新的客戶端連接通道描述符                   //
//  path 準備保存本地文件的路徑信息                            //
//  fileName 根據(jù)接收報文中的文件名稱與本地路徑拼串而得到的返回文件信息          //
//  timeout  數(shù)據(jù)傳輸需要使用的延時參數(shù)                          //
//                                             //
//  返回數(shù)據(jù):                                       //
//  0 ---- 文件接收成功                                  //
//  -2 -- 文件無法創(chuàng)建,打開文件名稱失敗                          //
//  -1 -- 文件內(nèi)容內(nèi)容保存失敗                               //
//  ====================================================================================== ////
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 );
        // 對于接收到的第一條命令,打印該控制命令的全部內(nèi)容
 
        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;
        }
        // 對需要保存的本地文件,使用清空方式,創(chuàng)建新文件,既是該文件已經(jīng)存在
        // 也可以保證數(shù)據(jù)處理
 
 
        wLog(LOGINFO,"創(chuàng)建本地文件[%s]成功", fileName );
        break ;
      case 200 :  // 保存文件內(nèi)容
        blknum ++;
        maxBlk --;
        if(blknum == 1 || !maxBlk )wLog(LOGINFO, "接收數(shù)據(jù)[%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 : // 文件傳輸結(jié)束
        if( !maxBlk )
          wLog(LOGINFO, " 文件[%s]成功接收,共 [%d] 傳輸塊 ", fileName, blknum );
        else
          wLog(LOGERROR,"文件[%s]接收結(jié)束,差錯 [%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,"發(fā)送返回信息 [%s] 失敗 error [%d, %s]", ncb.sndcmd + 6, errno, strerror(errno) );
    }
    if(chkflg ) break ;
  }
 
  if(fd) close (fd);
 
  wLog(LOGINFO,"成功接收[%s]文件, 共 [%ld] 字節(jié)", fileName , fsize );
 
  return chkflg ;
}
 
 
//  ============================= 客戶端使用 多文件發(fā)送程序 =============================== ////
//                                              //
//  socket 方式文件發(fā)送程序,根據(jù)輸入的 netinfo 建立通信通道,然后按照以下要求發(fā)送文件   //
//  PUT100 發(fā)送文件基本信息                                 //
//  PUT200 發(fā)送文件內(nèi)容,根據(jù)要求循環(huán)執(zhí)行,......                      //
//  PUT300 數(shù)據(jù)發(fā)送結(jié)束                                   //
//                                              //
//  ======================================================================================= ////
 
//
// 在建立好的文件傳輸通道上,將一個文件數(shù)據(jù)發(fā)送到服務(wù)端,傳輸后,不需要關(guān)閉傳輸通道。
//
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) ;
  // 計算本文件的最大傳輸次數(shù)
  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,"發(fā)送[%d] [%s]失敗 error [%d, %s]", ncb.wlen, remoteFile , errno, strerror(errno) );
    chkflg = -2;
    goto mSend_END;
  }
  wLog(LOGINFO,"發(fā)送報文頭[%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,"接到返回數(shù)據(jù) [%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 ; // 本地文件已經(jīng)發(fā)送結(jié)束
 
    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,"發(fā)送 [%s] 失敗 error [%d, %s]", ncb.sndcmd , errno, strerror(errno) );
      chkflg = -1;
      goto mSend_END;
    }
    if( blknum == 1 || blknum == maxBlk )
      wLog(LOGINFO,"發(fā)送數(shù)據(jù)[%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,"發(fā)送 FileOver 失敗 error [%d, %s]", errno, strerror(errno) );
    chkflg = -1;
    goto mSend_END;
  }
  wLog(LOGINFO,"發(fā)送數(shù)據(jù)[%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, "接到返回數(shù)據(jù)[%s]成功", ncb.rcvcmd );
 
  wLog(LOGINFO, "傳輸[%s]-->[%s] [%d]塊,共 [%ld]字節(jié), 耗時 %ld 秒\n\n", localFile , remoteFile ,
      blknum, fsize , time(NULL) - start );
 
mSend_END:
  if(fd > 0) close(fd);
  // 關(guān)閉本文描述符和通信連接通道描述符
 
  return chkflg;
 
}
 
// ============================================= 多文件處理函數(shù) ====================================== //
//                                                   //
//                                                   //
// 多文件發(fā)送服務(wù)程序,本程序?qū)κ褂?":" 分隔的文件信息自動進行分解,然后將每一個文件          //
// 使用上述函數(shù)完成推送工作,在啊全部文件發(fā)送完畢后,程序?qū)l(fā)出 PUT500 傳輸結(jié)束命令。         //
//                                                   //
/////////////////////////////////////////////////////////////////////////////////////////////////////////
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 () 建立到服務(wù)器的連接通道
 
  if(sfd < 0 ) {
    wLog(LOGERROR,"建立到[%s]文件傳輸通道失敗 error [%d, %s]", netinfo , errno, strerror(errno) );
    return -4;
  }
  wLog(LOGINFO, "成功建立到[%s]發(fā)送通道[%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, ':');
  }
  // 對輸入的文件名稱進行分解,調(diào)用 cli_mput_sendFile() 函數(shù)進行數(shù)據(jù)發(fā)送。
 
 
  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,"發(fā)送 FileOver 失敗 error [%d, %s]", errno, strerror(errno) );
    chkflg = -1;
    goto cli_put_sendFile_END;
  }
  wLog(LOGINFO,"發(fā)送數(shù)據(jù)[%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, "接到返回數(shù)據(jù)[%s]成功", ncb.rcvcmd );
 
  wLog(LOGINFO, "共 [%d]個文件, 耗時 %ld 秒\n\n", fnum , time(NULL) - start );
 
 
cli_put_sendFile_END:
  if(sfd > 0) close(sfd);
  // 關(guān)閉本文描述符和通信連接通道描述符
 
  return chkflg;
}
 
 
//  ============================ 服務(wù)端使用 多文件傳輸程序 =============================== ////
//                                             //
//  socket 文件接收服務(wù)程序,對收到的通信報文進行分析。                  //
//  在收到 PUT100 命令后,將該數(shù)據(jù)域中的文件名稱與本地路徑拼寫得到完整的文件        //
//         路徑信息,打開本地文件。                         //
//  對 PUT200 數(shù)據(jù)域傳輸來的數(shù)據(jù)保存到本地文件中。                     //
//  收到 PUT300 命令,關(guān)閉當前傳輸文件。                          //
//  收到 PUT500 命令,TCP 文件傳輸過程結(jié)束,退出程序。                   //
//                                             //
//  文件傳輸服務(wù)端程序:                                  //
//  sfd  在 accept() 后獲取的新的客戶端連接通道描述符                   //
//  path 準備保存本地文件的路徑信息                            //
//  fileName 根據(jù)接收報文中的文件名稱與本地路徑拼串而得到的返回文件信息          //
//  timeout  數(shù)據(jù)傳輸需要使用的延時參數(shù)                          //
//                                             //
//  返回數(shù)據(jù):                                       //
//  0 ---- 文件接收成功                                  //
//  -2 -- 文件無法創(chuàng)建,打開文件名稱失敗                          //
//  -1 -- 文件內(nèi)容內(nèi)容保存失敗                               //
//                                             //
//  文件傳輸過程中,上傳的文件名稱有客戶端提供,但是文件保存路徑由服務(wù)器控制,以充分保證  //
//  服務(wù)器文件系統(tǒng)的安全,避免服務(wù)器上的文件被客戶端上傳文件惡意覆蓋。           //
//                                             //
//  ====================================================================================== ////
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 );
        // 對于接收到的第一條命令,打印該控制命令的全部內(nèi)容
 
        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);
        // 檢查傳輸來文件名稱中的路徑信息,得到基本文件名稱,將前面的路徑
        // 信息全部剔除,以保證本地文件的安全。當傳輸文件名稱帶有 ".." 標志
        // 的時候,將會對服務(wù)器文件系統(tǒng)產(chǎn)生影響,需要保證該問題不會出現(xiàn)。
 
        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 ++;
        // 對需要保存的本地文件,使用清空方式,創(chuàng)建新文件,既是該文件已經(jīng)存在
        // 也可以保證數(shù)據(jù)處理
 
        wLog(LOGINFO,"創(chuàng)建本地文件[%s]成功", localFile );
        break ;
      case 200 :  // 保存文件內(nèi)容
        blknum ++;
        maxBlk --;
        if(blknum == 1 || !maxBlk )wLog(LOGINFO, "接收數(shù)據(jù)[%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 : // 文件傳輸結(jié)束
        if( !maxBlk )
          wLog(LOGINFO, " 文件[%s]成功接收,共 [%d] 傳輸塊 ", localFile, blknum );
        else
          wLog(LOGERROR,"文件[%s]接收結(jié)束,差錯 [%d] 傳輸塊 ", localFile , maxBlk );
 
        close(fd);
        break ;
      case 500 : // 通信處理結(jié)束
        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,"發(fā)送返回信息 [%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 ;
}
 
 
// ================================================================================================== //
///////////////////////////////////以下為客戶端主動下載類程序///////////////////////////////////////////
//  ============================= 客戶端使用 文件發(fā)送程序 ================================= ////
//                                              //
//  socket 方式文件發(fā)送程序,根據(jù)輸入的 netinfo 建立通信通道,然后按照以下要求發(fā)送文件   //
//  GET100 發(fā)送文件下載請求,將遠程文件名稱和分塊尺寸上送主機,等主機回應(yīng)          //
//  GET200 接收文件內(nèi)容,根據(jù)要求循環(huán)執(zhí)行,......                      //
//  GET300 數(shù)據(jù)發(fā)送結(jié)束                                   //
//                                              //
//  ======================================================================================= ////
 
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 () 建立到服務(wù)器的連接通道
 
  if(sfd < 0 ) {
    wLog(LOGERROR,"建立到[%s]連接失敗 error [%d, %s]", netinfo , errno, strerror(errno) );
    return -4;
  }
  wLog(LOGINFO, "成功建立到[%s]發(fā)送通道[%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) ;
  // 計算本文件的最大傳輸次數(shù)
  if( fsize % blockSize ) maxBlk += 1;
  // 不足整塊的數(shù)據(jù),需要按一塊進行處理。
 
  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,"發(fā)送[%d] [%s]失敗 error [%d, %s]", ncb.wlen, remoteFile , errno, strerror(errno) );
    chkflg = -2;
    goto cli_get_sendFile_END;
  }
  wLog(LOGINFO, "發(fā)送報文頭[%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,"接到返回數(shù)據(jù) [%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 ; // 本地文件已經(jīng)發(fā)送結(jié)束
 
    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,"發(fā)送 [%s] 失敗 error [%d, %s]", ncb.sndcmd , errno, strerror(errno) );
      chkflg = -1;
      goto cli_get_sendFile_END;
    }
    if( blknum == 1 || blknum == maxBlk )
      wLog(LOGINFO, "發(fā)送數(shù)據(jù)[%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,"發(fā)送 FileOver 失敗 error [%d, %s]", errno, strerror(errno) );
    chkflg = -1;
    goto cli_get_sendFile_END;
  }
  wLog(LOGINFO, "發(fā)送數(shù)據(jù)[%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, "接到返回數(shù)據(jù)[%s]成功", ncb.rcvcmd );
 
  wLog(LOGINFO, "傳輸[%s]-->[%s] [%d]塊,共 [%ld]字節(jié), 耗時 %ld 秒\n\n", localFile , remoteFile ,
      blknum, fsize , time(NULL) - start );
 
cli_get_sendFile_END:
  if(sfd > 0) close(sfd);
  if(fd > 0) close(fd);
  // 關(guān)閉本文描述符和通信連接通道描述符
 
  return chkflg;
}
 
 
//  ============================ 服務(wù)端使用 文件傳輸程序 ================================= ////
//                                             //
//  socket 文件接收服務(wù)程序,對收到的通信報文進行分析。                  //
//  在收到 GET100 命令后,將該數(shù)據(jù)域中的文件名稱與本地路徑拼寫得到完整的文件        //
//         路徑信息,打開本地文件。                         //
//  對 GET200 數(shù)據(jù)域傳輸來的數(shù)據(jù)保存到本地文件中。                     //
//  收到 GET300 命令,關(guān)閉本地文件,傳輸過程結(jié)束。                     //
//                                             //
//  文件傳輸服務(wù)端程序:                                  //
//  sfd  在 accept() 后獲取的新的客戶端連接通道描述符                   //
//  path 準備保存本地文件的路徑信息                            //
//  fileName 根據(jù)接收報文中的文件名稱與本地路徑拼串而得到的返回文件信息          //
//  timeout  數(shù)據(jù)傳輸需要使用的延時參數(shù)                          //
//                                             //
//  返回數(shù)據(jù):                                       //
//  0 ---- 文件接收成功                                  //
//  -2 -- 文件無法創(chuàng)建,打開文件名稱失敗                          //
//  -1 -- 文件內(nèi)容內(nèi)容保存失敗                               //
//  ====================================================================================== ////
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 );
        // 對于接收到的第一條命令,打印該控制命令的全部內(nèi)容
 
        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;
        }
        // 對需要保存的本地文件,使用清空方式,創(chuàng)建新文件,既是該文件已經(jīng)存在
        // 也可以保證數(shù)據(jù)處理
 
        wLog(LOGINFO, "創(chuàng)建本地文件[%s]成功", fileName );
        break ;
      case 200 :  // 保存文件內(nèi)容
        blknum ++;
        maxBlk --;
        if(blknum == 1 || !maxBlk )wLog(LOGINFO, "接收數(shù)據(jù)[%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 : // 文件傳輸結(jié)束
        if( !maxBlk )
          wLog(LOGINFO, " 文件[%s]成功接收,共 [%d] 傳輸塊 ", fileName, blknum );
        else
          wLog(LOGERROR,"文件[%s]接收結(jié)束,差錯 [%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,"發(fā)送返回信息 [%s] 失敗 error [%d, %s]", ncb.sndcmd + 6, errno, strerror(errno) );
    }
    if(chkflg ) break ;
  }
 
  if(fd) close (fd);
 
  wLog(LOGINFO, "成功接收[%s]文件, 共 [%ld] 字節(jié)", fileName , fsize );
 
  return chkflg ;
}
 
 
//  ============================= 客戶端使用 多文件發(fā)送程序 =============================== ////
//                                              //
//  socket 方式文件發(fā)送程序,根據(jù)輸入的 netinfo 建立通信通道,然后按照以下要求發(fā)送文件   //
//  GET100 發(fā)送文件基本信息                                 //
//  GET200 發(fā)送文件內(nèi)容,根據(jù)要求循環(huán)執(zhí)行,......                      //
//  GET300 數(shù)據(jù)發(fā)送結(jié)束                                   //
//                                              //
//  ======================================================================================= ////
 
//
// 在建立好的文件傳輸通道上,將一個文件數(shù)據(jù)發(fā)送到服務(wù)端,傳輸后,不需要關(guān)閉傳輸通道。
//
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) ;
  // 計算本文件的最大傳輸次數(shù)
  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,"發(fā)送[%d] [%s]失敗 error [%d, %s]", ncb.wlen, remoteFile , errno, strerror(errno) );
    chkflg = -2;
    goto mSend_END;
  }
  wLog(LOGINFO,"發(fā)送報文頭[%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,"接到返回數(shù)據(jù) [%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 ; // 本地文件已經(jīng)發(fā)送結(jié)束
 
    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,"發(fā)送 [%s] 失敗 error [%d, %s]", ncb.sndcmd , errno, strerror(errno) );
      chkflg = -1;
      goto mSend_END;
    }
    if( blknum == 1 || blknum == maxBlk )
      wLog(LOGINFO,"發(fā)送數(shù)據(jù)[%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,"發(fā)送 FileOver 失敗 error [%d, %s]", errno, strerror(errno) );
    chkflg = -1;
    goto mSend_END;
  }
  wLog(LOGINFO,"發(fā)送數(shù)據(jù)[%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, "接到返回數(shù)據(jù)[%s]成功", ncb.rcvcmd );
 
  wLog(LOGINFO, "傳輸[%s]-->[%s] [%d]塊,共 [%ld]字節(jié), 耗時 %ld 秒\n\n", localFile , remoteFile ,
      blknum, fsize , time(NULL) - start );
 
 
mSend_END:
  if(fd > 0) close(fd);
  // 關(guān)閉本文描述符和通信連接通道描述符
 
  return chkflg;
 
}
 
// ============================================= 多文件處理函數(shù) ====================================== //
//                                                   //
//                                                   //
// 多文件發(fā)送服務(wù)程序,本程序?qū)κ褂?":" 分隔的文件信息自動進行分解,然后將每一個文件          //
// 使用上述函數(shù)完成推送工作,在啊全部文件發(fā)送完畢后,程序?qū)l(fā)出 get500 傳輸結(jié)束命令。         //
//                                                   //
/////////////////////////////////////////////////////////////////////////////////////////////////////////
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 () 建立到服務(wù)器的連接通道
 
  if(sfd < 0 ) {
    wLog(LOGERROR,"建立到[%s]文件傳輸通道失敗 error [%d, %s]", netinfo , errno, strerror(errno) );
    return -4;
  }
  wLog(LOGINFO, "成功建立到[%s]發(fā)送通道[%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, ':');
  }
  // 對輸入的文件名稱進行分解,調(diào)用 cli_mget_sendFile() 函數(shù)進行數(shù)據(jù)發(fā)送。
 
 
  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,"發(fā)送 FileOver 失敗 error [%d, %s]", errno, strerror(errno) );
    chkflg = -1;
    goto cli_get_sendFile_END;
  }
  wLog(LOGINFO, "發(fā)送數(shù)據(jù)[%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, "接到返回數(shù)據(jù)[%s]成功", ncb.rcvcmd );
 
  wLog(LOGINFO, "共 [%d]個文件, 耗時 %ld 秒\n\n", fnum , time(NULL) - start );
 
cli_get_sendFile_END:
  if(sfd > 0) close(sfd);
  // 關(guān)閉本文描述符和通信連接通道描述符
 
  return chkflg;
}
 
 
//  ============================ 服務(wù)端使用 多文件傳輸程序 =============================== ////
//                                             //
//  socket 文件接收服務(wù)程序,對收到的通信報文進行分析。                  //
//  在收到 GET100 命令后,將該數(shù)據(jù)域中的文件名稱與本地路徑拼寫得到完整的文件        //
//         路徑信息,打開本地文件。                         //
//  對 GET200 數(shù)據(jù)域傳輸來的數(shù)據(jù)保存到本地文件中。                     //
//  收到 GET300 命令,關(guān)閉當前傳輸文件。                          //
//  收到 get500 命令,TCP 文件傳輸過程結(jié)束,退出程序。                   //
//                                             //
//  文件傳輸服務(wù)端程序:                                  //
//  sfd  在 accept() 后獲取的新的客戶端連接通道描述符                   //
//  path 準備保存本地文件的路徑信息                            //
//  fileName 根據(jù)接收報文中的文件名稱與本地路徑拼串而得到的返回文件信息          //
//  timeout  數(shù)據(jù)傳輸需要使用的延時參數(shù)                          //
//                                             //
//  返回數(shù)據(jù):                                       //
//  0 ---- 文件接收成功                                  //
//  -2 -- 文件無法創(chuàng)建,打開文件名稱失敗                          //
//  -1 -- 文件內(nèi)容內(nèi)容保存失敗                               //
//                                             //
//  文件傳輸過程中,上傳的文件名稱有客戶端提供,但是文件保存路徑由服務(wù)器控制,以充分保證  //
//  服務(wù)器文件系統(tǒng)的安全,避免服務(wù)器上的文件被客戶端上傳文件惡意覆蓋。           //
//                                             //
//  ====================================================================================== ////
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 );
        // 對于接收到的第一條命令,打印該控制命令的全部內(nèi)容
 
        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);
        // 檢查傳輸來文件名稱中的路徑信息,得到基本文件名稱,將前面的路徑
        // 信息全部剔除,以保證本地文件的安全。當傳輸文件名稱帶有 ".." 標志
        // 的時候,將會對服務(wù)器文件系統(tǒng)產(chǎn)生影響,需要保證該問題不會出現(xiàn)。
 
        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 ++;
        // 對需要保存的本地文件,使用清空方式,創(chuàng)建新文件,既是該文件已經(jīng)存在
        // 也可以保證數(shù)據(jù)處理
        wLog(LOGINFO, "創(chuàng)建本地文件[%s]成功", localFile );
        break ;
      case 200 :  // 保存文件內(nèi)容
        blknum ++;
        maxBlk --;
        if(blknum == 1 || !maxBlk )wLog(LOGINFO, "接收數(shù)據(jù)[%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 : // 文件傳輸結(jié)束
        if( !maxBlk )
          wLog(LOGINFO, " 文件[%s]成功接收,共 [%d] 傳輸塊 ", localFile, blknum );
        else
          wLog(LOGERROR,"文件[%s]接收結(jié)束,差錯 [%d] 傳輸塊 ", localFile , maxBlk );
 
        close(fd);
        break ;
      case 500 : // 通信處理結(jié)束
        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,"發(fā)送返回信息 [%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

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助。

相關(guān)文章

  • C++實現(xiàn)和電腦對戰(zhàn)三子棋實例

    C++實現(xiàn)和電腦對戰(zhàn)三子棋實例

    大家好,本篇文章主要講的是C++實現(xiàn)和電腦對戰(zhàn)三子棋實例,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • VC解析XML文件-CMarkup的使用詳解

    VC解析XML文件-CMarkup的使用詳解

    本篇文章是對VC解析XML文件-CMarkup的使用進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • C++常用語句簡介

    C++常用語句簡介

    這篇文章主要介紹了C++常用語句簡介,文章將要介紹的常用語句有聲明變量、賦值語句、cin、cout語句、庫函數(shù)、自定義函數(shù),需要的朋友可以參考一下,希望對你有所幫助
    2021-11-11
  • 詳解C++11中的線程鎖和條件變量

    詳解C++11中的線程鎖和條件變量

    C++ 11允許開發(fā)者們以標準的、不依賴于平臺的方式編寫多線程程序。這篇文章概述了標準庫對于線程和同步操作機制的支持。這些都是非常重要的知識,希望讀者們可以認真看一下
    2021-06-06
  • C++實現(xiàn)將輸入復(fù)制到輸出的方法

    C++實現(xiàn)將輸入復(fù)制到輸出的方法

    這篇文章主要介紹了C++實現(xiàn)將輸入復(fù)制到輸出的方法,實例分析了C++字符串轉(zhuǎn)換及輸入輸出操作的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-07-07
  • C++抽獎程序?qū)崿F(xiàn)方法

    C++抽獎程序?qū)崿F(xiàn)方法

    這篇文章主要介紹了C++抽獎程序?qū)崿F(xiàn)方法,實例分析了C++隨機數(shù)的生成技巧與抽獎程序的實現(xiàn)方法,需要的朋友可以參考下
    2015-07-07
  • C語言 scanf輸入多個數(shù)字只能以逗號分隔的操作

    C語言 scanf輸入多個數(shù)字只能以逗號分隔的操作

    這篇文章主要介紹了C語言 scanf輸入多個數(shù)字只能以逗號分隔的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 詳解C語言中的char數(shù)據(jù)類型及其與int類型的轉(zhuǎn)換

    詳解C語言中的char數(shù)據(jù)類型及其與int類型的轉(zhuǎn)換

    這篇文章主要介紹了詳解C語言中的char數(shù)據(jù)類型及其與int類型的轉(zhuǎn)換,是C語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-08-08
  • 詳解C語言編程之thread多線程

    詳解C語言編程之thread多線程

    這篇文章主要為大家介紹了C語言編程之thread多線程,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-12-12
  • c語言如何實現(xiàn)DES加密解密

    c語言如何實現(xiàn)DES加密解密

    這篇文章主要介紹了c語言如何實現(xiàn)DES加密解密問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04

最新評論