C++文件上傳、下載工具
更新時(shí)間:2016年05月15日 14:59:42 作者:逍遙天下1688
這篇文章主要為大家詳細(xì)介紹了C++文件上傳、下載工具的相關(guān)資料,感興趣的小伙伴們可以參考一下
本文實(shí)例為大家分享了C++文件上傳下載的實(shí)現(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 // 通信報(bào)文頭信息長(zhǎng)度
#define CMDINFO 6 // 空值命令 PUT GET
#define CMD
#define MAXKB 16
#define NCMD 32
#define NFILE 128
// tcp 通信命令行緩沖區(qū)
typedef struct tcpCmd {
int len; // 命令行長(zhǎng)度
char cmd[NCMD+1]; // 命令行緩沖區(qū)
} tcpCmd;
struct tcpBuffer {
int rlen; // 接收數(shù)據(jù)長(zhǎng)度
int wlen; // 發(fā)送數(shù)據(jù)長(zhǎng)度
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 ]; // 報(bào)文緩沖區(qū), 包含命令控制串和實(shí)際報(bào)文數(shù)據(jù)
} ncb;
// ////////////////////////////////////////////////////////////////////////////////////////////// ////
// //
// 根據(jù)報(bào)文頭數(shù)據(jù)要求,接收一個(gè)通信數(shù)據(jù)。 //
// 程序首先按照要求讀取 headlen 長(zhǎng)度的長(zhǎng)度包數(shù)據(jù),然后再次從網(wǎng)絡(luò)上讀取真正長(zhǎng)度的數(shù)據(jù)包。 //
// //
// 數(shù)據(jù)接收函數(shù)分兩次進(jìn)行處理,返回?cái)?shù)據(jù) sData 中已經(jīng)不再包含 6位通信長(zhǎng)度數(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 延時(shí)[%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,"讀取通信報(bào)文長(zhǎng)度[%s]失敗, faile [%d, %s]", temp, errno, strerror(errno) );
return -1;
}
if(sLen < 1 || sLen > MaxLen ){
if(sLen > MaxLen ) wLog(LOGERROR,"報(bào)文長(zhǎng)度[%s]錯(cuò)誤,數(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ù)沒(méi)有處理完時(shí),程序打印錯(cuò)誤日志信息 */
return(sLen-left_bytes);
}
//
// 數(shù)據(jù)發(fā)送程序,在指定的延時(shí)內(nèi)將指定長(zhǎng)度的數(shù)據(jù)包發(fā)送到 sfd 上。
// 發(fā)送數(shù)據(jù)需要將報(bào)文長(zhǎng)度保存在 sData 中,發(fā)送長(zhǎng)度比實(shí)際的報(bào)文多出長(zhǎng)度域 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 延時(shí)[%d] 結(jié)束, faile [%d, %s]", sTime, errno, strerror(errno) );
return -1;
}
// 檢查通信鏈路的 寫(xiě)狀態(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);
}
// ============================= 客戶(hù)端使用 文件發(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);
// 申請(qǐng) 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]打開(kāi)失敗 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, "成功打開(kāi)本地文件[%s], size[%ld] ", localFile, fsize );
maxBlk = (int ) ( (fsize ) / blockSize) ;
// 計(jì)算本文件的最大傳輸次數(shù)
if( fsize % blockSize ) maxBlk += 1;
// 不足整塊的數(shù)據(jù),需要按一塊進(jìn)行處理。
memset(&ncb , 0x00 , sizeof (struct tcpBuffer));
// 準(zhǔn)備發(fā)送文件控制命令串, 告訴對(duì)方準(zhǔn)備發(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ā)送報(bào)文頭[%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,"遠(yuǎn)程保存[%s]失敗 error [%d, %s]", remoteFile , errno, strerror(errno) );
chkflg = -2;
goto cli_put_sendFile_END;
}
wLog(LOGINFO,"接到返回?cái)?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,"遠(yuǎn)程接收 [%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,"遠(yuǎn)程接收 FileOver 失敗 error [%d, %s]", errno, strerror(errno) );
chkflg = -1;
goto cli_put_sendFile_END;
}
wLog(LOGINFO, "接到返回?cái)?shù)據(jù)[%s]成功", ncb.rcvcmd );
wLog(LOGINFO, "傳輸[%s]-->[%s] [%d]塊,共 [%ld]字節(jié), 耗時(shí) %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ù)程序,對(duì)收到的通信報(bào)文進(jìn)行分析。 //
// 在收到 PUT100 命令后,將該數(shù)據(jù)域中的文件名稱(chēng)與本地路徑拼寫(xiě)得到完整的文件 //
// 路徑信息,打開(kāi)本地文件。 //
// 對(duì) PUT200 數(shù)據(jù)域傳輸來(lái)的數(shù)據(jù)保存到本地文件中。 //
// 收到 PUT300 命令,關(guān)閉本地文件,傳輸過(guò)程結(jié)束。 //
// //
// 文件傳輸服務(wù)端程序: //
// sfd 在 accept() 后獲取的新的客戶(hù)端連接通道描述符 //
// path 準(zhǔn)備保存本地文件的路徑信息 //
// fileName 根據(jù)接收?qǐng)?bào)文中的文件名稱(chēng)與本地路徑拼串而得到的返回文件信息 //
// timeout 數(shù)據(jù)傳輸需要使用的延時(shí)參數(shù) //
// //
// 返回?cái)?shù)據(jù): //
// 0 ---- 文件接收成功 //
// -2 -- 文件無(wú)法創(chuàng)建,打開(kāi)文件名稱(chē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] 錯(cuò)誤 ,程序退出. ", ncb.sndcmd+6 );
memcpy(ncb.rcvcmd+23, "01", 2);
chkflg = -3;
}
switch (Nstr_int(ncb.buff + 3, 3)){
// 獲取 PUT 后面的命令控制字,下面分析該控制字進(jìn)行工作
case 100 : // 開(kāi)始接收文件,打開(kāi)本地文件
wLog(LOGINFO, "接收管理報(bào)文[%s]成功", ncb.buff );
// 對(duì)于接收到的第一條命令,打印該控制命令的全部?jī)?nèi)容
ptr = strchr(ncb.buff, ':');
if(ptr) memcpy(tfile, ncb.buff+19, ptr - (char *)ncb.buff - 19);
else strcpy(tfile, ncb.buff+19);
// 獲取傳輸來(lái)的文件名稱(chēng)
ptr = strrchr(tfile, '/');
if(ptr) strcpy(bfile, ptr+1);
else strcpy(bfile, tfile);
// 檢查傳輸來(lái)文件名稱(chēng)中的路徑信息,得到基本文件名稱(chēng),將前面的路徑
// 信息全部剔除,以保證本地文件的安全。
if( (ptr = strrchr(ncb.buff , ':') ) != NULL ) maxBlk = atoi (ptr +1);
if( path ) sprintf(fileName, "%s/%s", path, bfile);
else strcpy(fileName, bfile );
// 與本地保存路徑拼串,獲得本地文件名稱(chēng)
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;
}
// 對(duì)需要保存的本地文件,使用清空方式,創(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é)束,差錯(cuò) [%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 ;
}
// ============================= 客戶(hù)端使用 多文件發(fā)送程序 =============================== ////
// //
// socket 方式文件發(fā)送程序,根據(jù)輸入的 netinfo 建立通信通道,然后按照以下要求發(fā)送文件 //
// PUT100 發(fā)送文件基本信息 //
// PUT200 發(fā)送文件內(nèi)容,根據(jù)要求循環(huán)執(zhí)行,...... //
// PUT300 數(shù)據(jù)發(fā)送結(jié)束 //
// //
// ======================================================================================= ////
//
// 在建立好的文件傳輸通道上,將一個(gè)文件數(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]打開(kāi)失敗 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, "成功打開(kāi)本地文件[%s], size[%ld] ", localFile, fsize );
maxBlk = (int ) ( (fsize ) / blockSize) ;
// 計(jì)算本文件的最大傳輸次數(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ā)送報(bào)文頭[%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,"遠(yuǎn)程保存[%s]失敗 error [%d, %s]", remoteFile , errno, strerror(errno) );
chkflg = -2;
goto mSend_END;
}
wLog(LOGINFO,"接到返回?cái)?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,"遠(yuǎn)程接收 [%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,"遠(yuǎn)程接收 FileOver 失敗 error [%d, %s]", errno, strerror(errno) );
chkflg = -1;
goto mSend_END;
}
wLog(LOGINFO, "接到返回?cái)?shù)據(jù)[%s]成功", ncb.rcvcmd );
wLog(LOGINFO, "傳輸[%s]-->[%s] [%d]塊,共 [%ld]字節(jié), 耗時(shí) %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ū)κ褂?":" 分隔的文件信息自動(dòng)進(jìn)行分解,然后將每一個(gè)文件 //
// 使用上述函數(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]; // 本地文件名稱(chēng)
char rFile[NFILE+1]; // 遠(yuǎn)程文件名稱(chēng)
}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, ':');
}
// 對(duì)輸入的文件名稱(chēng)進(jìn)行分解,調(diào)用 cli_mput_sendFile() 函數(shù)進(jìn)行數(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,"遠(yuǎn)程接收 FileOver 失敗 error [%d, %s]", errno, strerror(errno) );
chkflg = -1;
goto cli_put_sendFile_END;
}
wLog(LOGINFO, "接到返回?cái)?shù)據(jù)[%s]成功", ncb.rcvcmd );
wLog(LOGINFO, "共 [%d]個(gè)文件, 耗時(shí) %ld 秒\n\n", fnum , time(NULL) - start );
cli_put_sendFile_END:
if(sfd > 0) close(sfd);
// 關(guān)閉本文描述符和通信連接通道描述符
return chkflg;
}
// ============================ 服務(wù)端使用 多文件傳輸程序 =============================== ////
// //
// socket 文件接收服務(wù)程序,對(duì)收到的通信報(bào)文進(jìn)行分析。 //
// 在收到 PUT100 命令后,將該數(shù)據(jù)域中的文件名稱(chēng)與本地路徑拼寫(xiě)得到完整的文件 //
// 路徑信息,打開(kāi)本地文件。 //
// 對(duì) PUT200 數(shù)據(jù)域傳輸來(lái)的數(shù)據(jù)保存到本地文件中。 //
// 收到 PUT300 命令,關(guān)閉當(dāng)前傳輸文件。 //
// 收到 PUT500 命令,TCP 文件傳輸過(guò)程結(jié)束,退出程序。 //
// //
// 文件傳輸服務(wù)端程序: //
// sfd 在 accept() 后獲取的新的客戶(hù)端連接通道描述符 //
// path 準(zhǔn)備保存本地文件的路徑信息 //
// fileName 根據(jù)接收?qǐng)?bào)文中的文件名稱(chēng)與本地路徑拼串而得到的返回文件信息 //
// timeout 數(shù)據(jù)傳輸需要使用的延時(shí)參數(shù) //
// //
// 返回?cái)?shù)據(jù): //
// 0 ---- 文件接收成功 //
// -2 -- 文件無(wú)法創(chuàng)建,打開(kāi)文件名稱(chēng)失敗 //
// -1 -- 文件內(nèi)容內(nèi)容保存失敗 //
// //
// 文件傳輸過(guò)程中,上傳的文件名稱(chēng)有客戶(hù)端提供,但是文件保存路徑由服務(wù)器控制,以充分保證 //
// 服務(wù)器文件系統(tǒng)的安全,避免服務(wù)器上的文件被客戶(hù)端上傳文件惡意覆蓋。 //
// //
// ====================================================================================== ////
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] 錯(cuò)誤 ,程序退出. ", ncb.sndcmd+6 );
memcpy(ncb.rcvcmd+23, "01", 2);
chkflg = -3;
}
switch (Nstr_int(ncb.buff + 3, 3)){
// 獲取 PUT 后面的命令控制字,下面分析該控制字進(jìn)行工作
case 100 : // 開(kāi)始接收文件,打開(kāi)本地文件
blknum = maxBlk = 0 ;
wLog(LOGINFO, "接收管理報(bào)文[%s]成功", ncb.buff );
// 對(duì)于接收到的第一條命令,打印該控制命令的全部?jī)?nèi)容
ptr = strchr(ncb.buff, ':');
if(ptr) memcpy(tfile, ncb.buff+19, ptr - (char *)ncb.buff - 19);
else strcpy(tfile, ncb.buff+19);
// 獲取傳輸來(lái)的文件名稱(chēng)
ptr = strrchr(tfile, '/');
if(ptr) strcpy(bfile, ptr+1);
else strcpy(bfile, tfile);
// 檢查傳輸來(lái)文件名稱(chēng)中的路徑信息,得到基本文件名稱(chēng),將前面的路徑
// 信息全部剔除,以保證本地文件的安全。當(dāng)傳輸文件名稱(chēng)帶有 ".." 標(biāo)志
// 的時(shí)候,將會(huì)對(duì)服務(wù)器文件系統(tǒng)產(chǎn)生影響,需要保證該問(wèn)題不會(huì)出現(xiàn)。
if( (ptr = strrchr(ncb.buff , ':') ) != NULL ) maxBlk = atoi (ptr +1);
// 從命令報(bào)文中得到文件傳輸塊信息。
if( path ) sprintf(localFile, "%s/%s", path, bfile);
else strcpy(localFile, bfile );
// 與本地保存路徑拼串,獲得本地文件名稱(chēng)
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 ++;
// 對(duì)需要保存的本地文件,使用清空方式,創(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é)束,差錯(cuò) [%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]文件, 耗時(shí) [%ld] 秒 ", fnum , time(NULL) - start );
return chkflg ;
}
// ================================================================================================== //
///////////////////////////////////以下為客戶(hù)端主動(dòng)下載類(lèi)程序///////////////////////////////////////////
// ============================= 客戶(hù)端使用 文件發(fā)送程序 ================================= ////
// //
// socket 方式文件發(fā)送程序,根據(jù)輸入的 netinfo 建立通信通道,然后按照以下要求發(fā)送文件 //
// GET100 發(fā)送文件下載請(qǐng)求,將遠(yuǎn)程文件名稱(chēng)和分塊尺寸上送主機(jī),等主機(jī)回應(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);
// 申請(qǐng) 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]打開(kāi)失敗 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, "成功打開(kāi)本地文件[%s], size[%ld] ", localFile, fsize );
maxBlk = (int ) ( (fsize ) / blockSize) ;
// 計(jì)算本文件的最大傳輸次數(shù)
if( fsize % blockSize ) maxBlk += 1;
// 不足整塊的數(shù)據(jù),需要按一塊進(jìn)行處理。
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ā)送報(bào)文頭[%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,"遠(yuǎn)程保存[%s]失敗 error [%d, %s]", remoteFile , errno, strerror(errno) );
chkflg = -2;
goto cli_get_sendFile_END;
}
wLog(LOGINFO,"接到返回?cái)?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,"遠(yuǎn)程接收 [%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,"遠(yuǎn)程接收 FileOver 失敗 error [%d, %s]", errno, strerror(errno) );
chkflg = -1;
goto cli_get_sendFile_END;
}
wLog(LOGINFO, "接到返回?cái)?shù)據(jù)[%s]成功", ncb.rcvcmd );
wLog(LOGINFO, "傳輸[%s]-->[%s] [%d]塊,共 [%ld]字節(jié), 耗時(shí) %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ù)程序,對(duì)收到的通信報(bào)文進(jìn)行分析。 //
// 在收到 GET100 命令后,將該數(shù)據(jù)域中的文件名稱(chēng)與本地路徑拼寫(xiě)得到完整的文件 //
// 路徑信息,打開(kāi)本地文件。 //
// 對(duì) GET200 數(shù)據(jù)域傳輸來(lái)的數(shù)據(jù)保存到本地文件中。 //
// 收到 GET300 命令,關(guān)閉本地文件,傳輸過(guò)程結(jié)束。 //
// //
// 文件傳輸服務(wù)端程序: //
// sfd 在 accept() 后獲取的新的客戶(hù)端連接通道描述符 //
// path 準(zhǔn)備保存本地文件的路徑信息 //
// fileName 根據(jù)接收?qǐng)?bào)文中的文件名稱(chēng)與本地路徑拼串而得到的返回文件信息 //
// timeout 數(shù)據(jù)傳輸需要使用的延時(shí)參數(shù) //
// //
// 返回?cái)?shù)據(jù): //
// 0 ---- 文件接收成功 //
// -2 -- 文件無(wú)法創(chuàng)建,打開(kāi)文件名稱(chē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] 錯(cuò)誤 ,程序退出. ", ncb.sndcmd+6 );
memcpy(ncb.rcvcmd+23, "01", 2);
chkflg = -3;
}
switch (Nstr_int(ncb.buff + 3, 3)){
// 獲取 get 后面的命令控制字,下面分析該控制字進(jìn)行工作
case 100 : // 開(kāi)始接收文件,打開(kāi)本地文件
wLog(LOGINFO, "接收管理報(bào)文[%s]成功", ncb.buff );
// 對(duì)于接收到的第一條命令,打印該控制命令的全部?jī)?nèi)容
ptr = strchr(ncb.buff, ':');
if(ptr) memcpy(tfile, ncb.buff+19, ptr - (char *)ncb.buff - 19);
else strcpy(tfile, ncb.buff+19);
// 獲取傳輸來(lái)的文件名稱(chēng)
ptr = strrchr(tfile, '/');
if(ptr) strcpy(bfile, ptr+1);
else strcpy(bfile, tfile);
// 檢查傳輸來(lái)文件名稱(chēng)中的路徑信息,得到基本文件名稱(chēng),將前面的路徑
// 信息全部剔除,以保證本地文件的安全。
if( (ptr = strrchr(ncb.buff , ':') ) != NULL ) maxBlk = atoi (ptr +1);
if( path ) sprintf(fileName, "%s/%s", path, bfile);
else strcpy(fileName, bfile );
// 與本地保存路徑拼串,獲得本地文件名稱(chēng)
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;
}
// 對(duì)需要保存的本地文件,使用清空方式,創(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é)束,差錯(cuò) [%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 ;
}
// ============================= 客戶(hù)端使用 多文件發(fā)送程序 =============================== ////
// //
// socket 方式文件發(fā)送程序,根據(jù)輸入的 netinfo 建立通信通道,然后按照以下要求發(fā)送文件 //
// GET100 發(fā)送文件基本信息 //
// GET200 發(fā)送文件內(nèi)容,根據(jù)要求循環(huán)執(zhí)行,...... //
// GET300 數(shù)據(jù)發(fā)送結(jié)束 //
// //
// ======================================================================================= ////
//
// 在建立好的文件傳輸通道上,將一個(gè)文件數(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]打開(kāi)失敗 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,"成功打開(kāi)本地文件[%s], size[%ld] ", localFile, fsize );
maxBlk = (int ) ( (fsize ) / blockSize) ;
// 計(jì)算本文件的最大傳輸次數(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ā)送報(bào)文頭[%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,"遠(yuǎn)程保存[%s]失敗 error [%d, %s]", remoteFile , errno, strerror(errno) );
chkflg = -2;
goto mSend_END;
}
wLog(LOGINFO,"接到返回?cái)?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,"遠(yuǎn)程接收 [%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,"遠(yuǎn)程接收 FileOver 失敗 error [%d, %s]", errno, strerror(errno) );
chkflg = -1;
goto mSend_END;
}
wLog(LOGINFO, "接到返回?cái)?shù)據(jù)[%s]成功", ncb.rcvcmd );
wLog(LOGINFO, "傳輸[%s]-->[%s] [%d]塊,共 [%ld]字節(jié), 耗時(shí) %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ū)κ褂?":" 分隔的文件信息自動(dòng)進(jìn)行分解,然后將每一個(gè)文件 //
// 使用上述函數(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]; // 本地文件名稱(chēng)
char rFile[NFILE+1]; // 遠(yuǎn)程文件名稱(chēng)
}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, ':');
}
// 對(duì)輸入的文件名稱(chēng)進(jìn)行分解,調(diào)用 cli_mget_sendFile() 函數(shù)進(jìn)行數(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,"遠(yuǎn)程接收 FileOver 失敗 error [%d, %s]", errno, strerror(errno) );
chkflg = -1;
goto cli_get_sendFile_END;
}
wLog(LOGINFO, "接到返回?cái)?shù)據(jù)[%s]成功", ncb.rcvcmd );
wLog(LOGINFO, "共 [%d]個(gè)文件, 耗時(shí) %ld 秒\n\n", fnum , time(NULL) - start );
cli_get_sendFile_END:
if(sfd > 0) close(sfd);
// 關(guān)閉本文描述符和通信連接通道描述符
return chkflg;
}
// ============================ 服務(wù)端使用 多文件傳輸程序 =============================== ////
// //
// socket 文件接收服務(wù)程序,對(duì)收到的通信報(bào)文進(jìn)行分析。 //
// 在收到 GET100 命令后,將該數(shù)據(jù)域中的文件名稱(chēng)與本地路徑拼寫(xiě)得到完整的文件 //
// 路徑信息,打開(kāi)本地文件。 //
// 對(duì) GET200 數(shù)據(jù)域傳輸來(lái)的數(shù)據(jù)保存到本地文件中。 //
// 收到 GET300 命令,關(guān)閉當(dāng)前傳輸文件。 //
// 收到 get500 命令,TCP 文件傳輸過(guò)程結(jié)束,退出程序。 //
// //
// 文件傳輸服務(wù)端程序: //
// sfd 在 accept() 后獲取的新的客戶(hù)端連接通道描述符 //
// path 準(zhǔn)備保存本地文件的路徑信息 //
// fileName 根據(jù)接收?qǐng)?bào)文中的文件名稱(chēng)與本地路徑拼串而得到的返回文件信息 //
// timeout 數(shù)據(jù)傳輸需要使用的延時(shí)參數(shù) //
// //
// 返回?cái)?shù)據(jù): //
// 0 ---- 文件接收成功 //
// -2 -- 文件無(wú)法創(chuàng)建,打開(kāi)文件名稱(chēng)失敗 //
// -1 -- 文件內(nèi)容內(nèi)容保存失敗 //
// //
// 文件傳輸過(guò)程中,上傳的文件名稱(chēng)有客戶(hù)端提供,但是文件保存路徑由服務(wù)器控制,以充分保證 //
// 服務(wù)器文件系統(tǒng)的安全,避免服務(wù)器上的文件被客戶(hù)端上傳文件惡意覆蓋。 //
// //
// ====================================================================================== ////
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] 錯(cuò)誤 ,程序退出. ", ncb.sndcmd+6 );
memcpy(ncb.rcvcmd+23, "01", 2);
chkflg = -3;
}
switch ( Nstr_int(ncb.buff + 3, 3) )
{
// 獲取 get 后面的命令控制字,下面分析該控制字進(jìn)行工作
case 100 : // 開(kāi)始接收文件,打開(kāi)本地文件
blknum = maxBlk = 0 ;
wLog(LOGINFO, "接收管理報(bào)文[%s]成功", ncb.buff );
// 對(duì)于接收到的第一條命令,打印該控制命令的全部?jī)?nèi)容
ptr = strchr(ncb.buff, ':');
if(ptr) memcpy(tfile, ncb.buff+19, ptr - (char *)ncb.buff - 19);
else strcpy(tfile, ncb.buff+19);
// 獲取傳輸來(lái)的文件名稱(chēng)
ptr = strrchr(tfile, '/');
if(ptr) strcpy(bfile, ptr+1);
else strcpy(bfile, tfile);
// 檢查傳輸來(lái)文件名稱(chēng)中的路徑信息,得到基本文件名稱(chēng),將前面的路徑
// 信息全部剔除,以保證本地文件的安全。當(dāng)傳輸文件名稱(chēng)帶有 ".." 標(biāo)志
// 的時(shí)候,將會(huì)對(duì)服務(wù)器文件系統(tǒng)產(chǎn)生影響,需要保證該問(wèn)題不會(huì)出現(xiàn)。
if( (ptr = strrchr(ncb.buff , ':') ) != NULL ) maxBlk = atoi (ptr +1);
// 從命令報(bào)文中得到文件傳輸塊信息。
if( path ) sprintf(localFile, "%s/%s", path, bfile);
else strcpy(localFile, bfile );
// 與本地保存路徑拼串,獲得本地文件名稱(chēng)
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 ++;
// 對(duì)需要保存的本地文件,使用清空方式,創(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é)束,差錯(cuò) [%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]文件, 耗時(shí) [%ld] 秒 ", fnum , time(NULL) - start );
return chkflg ;
}
#endif
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助。
您可能感興趣的文章:
- 用asp實(shí)現(xiàn)文件瀏覽、上傳、下載的程序
- Jsp頁(yè)面實(shí)現(xiàn)文件上傳下載類(lèi)代碼
- asp.net Web Services上傳和下載文件(完整代碼)
- Flex與.NET互操作 使用FileReference+HttpHandler實(shí)現(xiàn)文件上傳/下載
- asp.net 多文件上傳,兼容IE6/7/8,提供完整代碼下載
- Asp.net實(shí)現(xiàn)MVC處理文件的上傳下載功能實(shí)例教程
- JavaWeb實(shí)現(xiàn)文件上傳下載功能實(shí)例解析
- JAVA使用commos-fileupload實(shí)現(xiàn)文件上傳與下載實(shí)例解析
- 使用pcs api往免費(fèi)的百度網(wǎng)盤(pán)上傳下載文件的方法
- Java FTPClient實(shí)現(xiàn)文件上傳下載
相關(guān)文章
C++實(shí)現(xiàn)和電腦對(duì)戰(zhàn)三子棋實(shí)例
大家好,本篇文章主要講的是C++實(shí)現(xiàn)和電腦對(duì)戰(zhàn)三子棋實(shí)例,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話(huà)記得收藏一下2022-01-01
C++實(shí)現(xiàn)將輸入復(fù)制到輸出的方法
這篇文章主要介紹了C++實(shí)現(xiàn)將輸入復(fù)制到輸出的方法,實(shí)例分析了C++字符串轉(zhuǎn)換及輸入輸出操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07
C語(yǔ)言 scanf輸入多個(gè)數(shù)字只能以逗號(hào)分隔的操作
這篇文章主要介紹了C語(yǔ)言 scanf輸入多個(gè)數(shù)字只能以逗號(hào)分隔的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12
詳解C語(yǔ)言中的char數(shù)據(jù)類(lèi)型及其與int類(lèi)型的轉(zhuǎn)換
這篇文章主要介紹了詳解C語(yǔ)言中的char數(shù)據(jù)類(lèi)型及其與int類(lèi)型的轉(zhuǎn)換,是C語(yǔ)言入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-08-08

