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í)有所幫助。
您可能感興趣的文章:
- 用asp實現(xiàn)文件瀏覽、上傳、下載的程序
- Jsp頁面實現(xiàn)文件上傳下載類代碼
- asp.net Web Services上傳和下載文件(完整代碼)
- Flex與.NET互操作 使用FileReference+HttpHandler實現(xiàn)文件上傳/下載
- asp.net 多文件上傳,兼容IE6/7/8,提供完整代碼下載
- Asp.net實現(xiàn)MVC處理文件的上傳下載功能實例教程
- JavaWeb實現(xiàn)文件上傳下載功能實例解析
- JAVA使用commos-fileupload實現(xiàn)文件上傳與下載實例解析
- 使用pcs api往免費的百度網(wǎng)盤上傳下載文件的方法
- Java FTPClient實現(xiàn)文件上傳下載
相關(guān)文章
C語言 scanf輸入多個數(shù)字只能以逗號分隔的操作
這篇文章主要介紹了C語言 scanf輸入多個數(shù)字只能以逗號分隔的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12詳解C語言中的char數(shù)據(jù)類型及其與int類型的轉(zhuǎn)換
這篇文章主要介紹了詳解C語言中的char數(shù)據(jù)類型及其與int類型的轉(zhuǎn)換,是C語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-08-08