Vxworks ftp client 实现断点上传文件到服务器

本文详细介绍了如何使用FileZillaServerInterface实现FTP续传功能,包括获取文件大小、APPE命令续传到文件结尾的具体实现过程。通过基础下载、上传函数的测试,展示了错误处理及文件传输的细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

服务端推荐使用FileZilla Server Interface,支持获取文件大小SIZE命令和APPE续传到文件结尾。

具体实现函数

STATUS ftpAPPE(char host, / name of server host */
char user, / user name for host login */
char passwd, / password for host login */
char dirname, / directory to ‘cd’ to before sending command 网络的文件夹名*/
char filename, / filename to send with command */
char in_file / 上传的本地文件名 */);

下面是实现的过程 c文件

//基础下载函数 测试使用 返回错误 说明下载失败
int download(char host, / name of server host */
char user, / user name for host login */
char passwd, / password for host login */
char dirname, / directory to ‘cd’ to before sending command 网络的文件夹名*/
char filename, / filename to send with command */
char in_file / 下载的本地文件名 */) {
printf(“FTP ftpXfer RETR start!\n”);
int ctrlSock;
int dataSock;
char buf[512];
//char buf1[513];
int nBytes;
int nlocalwrite;
//原始文件 打开或者创建 。
int pFile;
STATUS status;
// char *in_file = “host:/c/test.text”;
pFile = open(in_file, O_WRONLY | O_CREAT, 0644);
ftpLibInit(5000L);
if (ftpXfer(host, user, passwd, “”, “RETR %s”, dirname, filename,
&ctrlSock, &dataSock) == ERROR)
return (ERROR);

while ((nBytes = read(dataSock, buf, sizeof(buf))) > 0 && (nlocalwrite
        = write(pFile, buf, nBytes)) > 0) {
    //  如果本地写的小于网络,说明错误 例如没有空间 。
    if (nlocalwrite < nBytes) {
        close(dataSock);
        close(pFile);
        close(ctrlSock);
        return (ERROR);
    }
    // memset(buf,0,sizeof(buf1));
    //memcpy(buf1, buf, nBytes);
    //printf("\r\n it is [%s]", buf);
}
close(dataSock);
close(pFile);
if (nBytes < 0 || nlocalwrite < 0) /* read error? */
    status = ERROR;

if (ftpReplyGet(ctrlSock, TRUE) != FTP_COMPLETE)
    status = ERROR;

if (ftpCommand(ctrlSock, "QUIT", 0, 0, 0, 0, 0, 0) != FTP_COMPLETE)
    status = ERROR;

close(ctrlSock);
return (status);

}
//基础上传函数 测试使用 返回错误 说明上传失败 可能上传了一部分 测试因为本地,速度很快。
int upload(char host, / name of server host */
char user, / user name for host login */
char passwd, / password for host login */
char dirname, / directory to ‘cd’ to before sending command 网络的文件夹名*/
char filename, / filename to send with command */
char in_file / 上传的本地文件名 */

) {
//上传 开始
printf(“FTP ftpXfer STOR start!\n”);
int ctrlSock = -1;
int dataSock = -1;
char buf[512];
//网络读写长度
int nBytes;
//本地写的长度 或者读
int nlocalread;
//原始文件 打开或者创建 读取。
int pFile;
STATUS status =OK;
// char *in_file = “host:/c/test.text”;
pFile = open(in_file, O_RDONLY, 0644);
if (pFile < 0) {
printf(“File error\n”);
return (ERROR);
}
ftpLibInit(5000L);
if (ftpXfer(host, user, passwd, “”, “STOR %s”, dirname, filename,
&ctrlSock, &dataSock) == ERROR)
return (ERROR);

while ((nlocalread = read(pFile, buf, sizeof(buf))) > 0 && (nBytes = write(
        dataSock, buf, nlocalread)) > 0) {
    //如果网络小于读取的文件,说明连接被服务器中止,则返回错误。
    if (nBytes < nlocalread) {
        close(dataSock);
        close(pFile);
        close(ctrlSock);
        return (ERROR);

    }
    // memset(buf,0,sizeof(buf1));
    //memcpy(buf1, buf, nBytes);
    //printf("\r\n it is [%s]", buf);
}

close(dataSock);
close(pFile);
if (nBytes < 0 || nlocalread < 0) /* read error? */
    status = ERROR;

if (ftpReplyGet(ctrlSock, TRUE) != FTP_COMPLETE)
    status = ERROR;

if (ftpCommand(ctrlSock, "QUIT", 0, 0, 0, 0, 0, 0) != FTP_COMPLETE)
    status = ERROR;

close(ctrlSock);
return (status);

}
//对ftpXfer改写增加获取长度命令。然后再此基础结合f读写函数上进行上传
LOCAL BOOL ftpTransientFatal(UINT32 reply);//ftp结果判断
UINT32 ftplTransientMaxRetryCount = 1; /* Retry just once for now */
UINT32 ftplTransientRetryInterval = 0; /* Default with no delay */
FUNCPTR _func_ftpTransientFatal = ftpTransientFatal;
LOCAL BOOL ftpTransientFatal(UINT32 reply /* Three digit code defined in RFC #959 */
) {
switch (reply) {
case (421): /* Service not available */
case (450): /* File unavailable */
case (451): /* error in processing */
case (452): /* insufficient storage */
{
/* yes, these are actually non-recoverable replies */
return (TRUE);
break;
}
/* attempt to retry the last command */
default:
return (FALSE);
}
}
//char * 转 long 专用 先偏移4,结尾可能有回车不一样; 这个函数不通用
long funs2l(char *s) {
long a = 0;
char *p = s;
p = p + 4;
while (*p != ‘\r’) {
a = a * 10 + *p - ‘0’;
p++;
}
return a;
}
//续传准备函数 注意参数cmd APPE %s
STATUS ftpXferAPPE(char host, / name of server host */
char user, / user name for host login */
char passwd, / password for host login */
char acct, / account for host login */
char cmd, / command to send to host */
char dirname, / directory to ‘cd’ to before sending command */
char filename, / filename to send with command */
int pCtrlSock, / where to return control socket fd */
int pDataSock, / where to return data socket fd, */
/* (NULL == don’t open data connection) */
long *psfilelen)

{
//上传
long sfilelen; /* 服务器文件大小 */
int replycode; /* 服务器对于SIZE 命令的回应码 */
char replyString[128]; /* 服务器对于SIZE 命令的回应值 */
memset(replyString, 0, 128);
int replyStringLength = 128; /* 服务器对于SIZE 命令的回应的最大长度,128应该够了 */
FAST int ctrlSock = ERROR;
FAST int dataSock = ERROR;
char *cmdsize = “SIZE %s”;
UINT32 ftpReply = 0;
UINT32 retryCount = 0;
int cmdResult;
struct fd_set readFds; /* Used by select for PORT method */
int width; /* Used by select for PORT method */
BOOL dataSockPassive = TRUE;

if (((ctrlSock = ftpHookup(host)) == ERROR) || (ftpLogin(ctrlSock, user,
        passwd, acct) != OK) || (ftpCommand(ctrlSock, "TYPE I", 0, 0, 0, 0,
        0, 0) != FTP_COMPLETE) || ((dirname[0] != EOS) && (ftpCommand(
        ctrlSock, "CWD %s", (int) dirname, 0, 0, 0, 0, 0) != FTP_COMPLETE))) {
    //有错误才执行这里

    /* Detected an error during command establishment */

    close(ctrlSock);
    return (ERROR);
}
//获取长度 有文件就是213 没有是550 其它返回错误。
replycode = ftpCommandEnhanced(ctrlSock, cmdsize, filename, 0, 0, 0, 0, 0,
        replyString, replyStringLength);

if (replycode == 213)
    sfilelen = funs2l(replyString);
else if (replycode == 550)
    sfilelen = 0L;
else {
    close(ctrlSock);
    return (ERROR);
}
printf("server file length %d\n", sfilelen);
if (psfilelen != NULL)
    *psfilelen = sfilelen;
/*
 * This is a special when an FTP command does not need to establish a
 * data connection.
 */
if (pDataSock == NULL) {
    if (ftpCommand(ctrlSock, cmd, (int) filename, 0, 0, 0, 0, 0)
            != FTP_COMPLETE) {

        close(ctrlSock);
        return (ERROR);
    }
}

/* 
 * At this point we are trying to establish the data socket.
 * We will first try using the modern, client-initiated PASV command.   
 * If PASV fails,  then we will fall back to the PORT command. 
 */
/*  Set up local data port and send the PORT command */
do {
    if ((dataSock = ftpDataConnInitPassiveMode(ctrlSock)) != ERROR) {

        dataSockPassive = TRUE; /* We do not need to listen() on the socket */
    } else {

        if ((dataSock = ftpDataConnInit(ctrlSock)) == ERROR) {

            close(ctrlSock);
            return (ERROR);
        } else
            dataSockPassive = FALSE; /* We will need to listen() on the socket */
    }
    /* Send the FTP command.  */
    cmdResult = ftpCommandEnhanced(ctrlSock, cmd, (int) filename, 0, 0, 0,
            0, 0, NULL, 0);
    if ((cmdResult / 100) != FTP_PRELIM) {
        /* 
         * The command has failed.  Close the data socket and decode the error.
         */
        close(dataSock);
        /* Check if something really bad happened: File not found, etc. */
        if ((cmdResult / 100) == FTP_ERROR) {

            close(ctrlSock);
            return (ERROR);
        }
        if ((cmdResult / 100) == FTP_TRANSIENT && _func_ftpTransientFatal
                != NULL) {

            if ((*_func_ftpTransientFatal)(cmdResult) == TRUE) {

                close(ctrlSock);
                errno = S_ftpLib_FATAL_TRANSIENT_RESPONSE;
                return (ERROR);
            }

        }
        if ((ftpReply = (cmdResult / 100)) == FTP_TRANSIENT) {
            /*
             * If the error was due to transient error (e.x. the data port
             * was not available) retry the command 
             * ftplTransientMaxRetryCount times.  
             */
            if (retryCount < ftplTransientMaxRetryCount) {
                ++retryCount;

                if (ftplTransientRetryInterval)
                    taskDelay(ftplTransientRetryInterval);
                continue; /* try another port */
            } else {
                /* Too many retries,  close socket and return failure */

                close(ctrlSock);
                errno = S_ftpLib_TRANSIENT_RETRY_LIMIT_EXCEEDED;
                return (ERROR);
            }
            /* Exit for any other error */

            close(ctrlSock);
            return (ERROR);
        }
    }
    if (dataSockPassive == FALSE) {
        /* At this point do a select on the data & control socket */

        FD_ZERO (&readFds);
        FD_SET (ctrlSock, &readFds);
        FD_SET (dataSock, &readFds);
        width = (dataSock > ctrlSock) ? dataSock : ctrlSock;
        width++;
        if (select(width, &readFds, NULL, NULL, NULL) == ERROR) {

            close(dataSock);
            close(ctrlSock);
            return (ERROR);
        }
        /* If the control socket is ready process it and take a decision,
         * try again or return error. If the data socket is ready call
         * ftpDataConnGet next.
         */
        if (FD_ISSET (ctrlSock, &readFds) && !FD_ISSET (dataSock, &readFds)) {
            close(dataSock);

            if ((ftpReply = ftpReplyGet(ctrlSock, FALSE)) == FTP_TRANSIENT)
                continue; /* Try another port */
            /* Regardless of response close sockets */

            (void) ftpCommand(ctrlSock, "QUIT", 0, 0, 0, 0, 0, 0);
            close(ctrlSock);
            return (ERROR);
        }
    } /* PORT method requires checking for data socket connection */
} while (ftpReply == FTP_TRANSIENT); /* Try again, we might need a different port */
/* If we used PASV mode,  then the socket is ready for use */
if (!dataSockPassive) {
    /* 
     * We used the PORT method to establish a connection.
     * The data socket connection is configured. Wait for the FTP server to connect
     * to us.
     */
    if ((dataSock = ftpDataConnGet(dataSock)) == ERROR) {

        close(ctrlSock);
        return (ERROR);
    }
}
/* Store the control and data sockets */
if (pCtrlSock != NULL)
    *pCtrlSock = ctrlSock;
if (pDataSock != NULL)
    *pDataSock = dataSock;
return (OK);

}
//续传 函数 ,优先被动模式,注意参数cmd APPE %s
STATUS ftpAPPE(
char host, / name of server host */
char user, / user name for host login */
char passwd, / password for host login */
char dirname, / directory to ‘cd’ to before sending command 网络的文件夹名*/
char filename, / filename to send with command */
char in_file / 上传的本地文件名 */)
{
//上传
printf(“FTP ftpXferAPPE start!\n”);
//char host = “192.168.200.254”; / name of server host */
//char user = “22422”; / user name for host login */
//char passwd = “22422”; / password for host login */
char acct = “”; / account for host login */
//char *in_file = “host:/c/cfg.ini”; //本地文件
// char cmdsize=”SIZE %s”; / command to send to host */
char *cmd = “APPE %s”;
//char dirname = “/”; / directory to ‘cd’ to before sending command */
//char filename = “test.txt”; / filename to send with command */
int ctrlSock = -1; /* where to return control socket fd */
int dataSock = -1; /* where to return data socket fd, // (NULL == don’t open data connection) */
long sfilelen = 0; /* 服务器文件大小 */
STATUS status = OK;
if (ftpXferAPPE(host, user, passwd, acct, cmd, dirname, filename,
&ctrlSock, &dataSock, &sfilelen) == ERROR)
return (ERROR);
//OK==0 TRUE==1
// int x= upload( host,user,passwd,dirname,filename,in_file);
//已经准备好了,APPE上传开始。 获得本地文件大小
FILE * pFile ;
pFile = fopen(in_file, “rb”);
if (pFile == NULL) {
fputs(“File open error”, stderr);
// 发送服务端错误码。
return ERROR;
}
fseek(pFile, 0, SEEK_END);
long lSize = ftell(pFile);
if (lSize <= sfilelen) {
printf(“upload aready OK no need upload %d,%d\n”, lSize,sfilelen);
close(dataSock);
close(pFile);
close(ctrlSock);
return (status);
}
//读取 上传
//网络读写长度
int nBytes;
//本地写的长度 或者读
int lBytes;

//复位 后移动也可以直接移动。当 读取个数为1时,返回值才是字节数
rewind(pFile);
fseek(pFile, sfilelen, SEEK_CUR);
char filebuffer[1024];
while ((lBytes = fread(filebuffer, 1, sizeof(filebuffer), pFile)) > 0
        && (nBytes = write(dataSock, filebuffer, lBytes)) > 0) {
    //如果网络小于读取的文件,一般说明连接被服务器中止,
    if (nBytes < lBytes) {
        //移动指针回去lBytes,前进nBytes
        fseek(pFile, -lBytes, SEEK_CUR);
        fseek(pFile, nBytes, SEEK_CUR);
    }
}
if (ferror ( pFile )) {
    printf("File read error.");
}
close(dataSock);
close(pFile);
if (nBytes < 0 || lBytes < 0) /* read error? */
    status = ERROR;
if (ftpReplyGet(ctrlSock, TRUE) != FTP_COMPLETE)
    status = ERROR;
if (ftpCommand(ctrlSock, "QUIT", 0, 0, 0, 0, 0, 0) != FTP_COMPLETE)
    status = ERROR;
printf("upload aready OK!\n");
close(ctrlSock);
return (status);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值