这一次我自己在Linux下写了一个简单的FTP客户端,支持的操作只有那些最常用的。这个程序已经通过简单的一些测试,目前实现的操作有:ls, dir, pwd, cd, ascii, binary, passive, get, put, delete, system, mkdir, rmdir, quit, bye. 另外,我用的了steven那本《UNIX网络编程卷1》的动态库,因为里面包含了一些API的封装,我无须理会这些API的返回码,所以程序需要包含unp.h这个头文件和链接libunp.so这个动态库。

  这个FTP客户端程序主要分两个模块,一个是ftp_socket.c,负责socket方面的操作,另外一个是ftp.c,负责FTP的操作实现。有参考了网上开源的项目中PORT和PASV部分的处理,其他其实都挺简单的。核心代码不到900行,其中有一些地方没考虑得很全面,一些处理得不够优雅,以后慢慢再修改,在git上已经给程序打了一个tag。直接贴代码了:

typedef.h : 声明和定义了一些类型和操作

#ifndef TYPEDEF_H
#define TYPEEF_Htypedef enum _Ret
{FTP_RET_OK,FTP_RET_OOM,FTP_RET_STOP,FTP_RET_INVALID_PARAMS,FTP_RET_FAIL
} FTP_Ret;#define DECLS_BEGIN
#define DECLS_END#define and &&
#define or  ||#define return_if_fail(p)    if (!(p))        \{printf("%s:%d Warning: "#p" failed.\n",\__func__, __LINE__); return; }
#define return_val_if_fail(p, ret)    if (!(p))    \{printf("%s:%d Warning: "#p" failed.\n",    \__func__, __LINE__); return (ret); }#define SAFE_FREE(p)    if (p != NULL) {free(p); p = NULL;}#endif

ftp_socket.h

#include "typedef.h"#ifndef FTP_SOCKET_H
#define FTP_SOCKET_HDECLS_BEGIN#define INVALID_SOCKET  (~0)#define FD_READ_BIT      0
#define FD_READ          (1 << FD_READ_BIT)
#define FD_WRITE_BIT     1
#define FD_WRITE         (1 << FD_WRITE_BIT)
#define FD_OOB_BIT       2
#define FD_OOB           (1 << FD_OOB_BIT)
#define FD_ACCEPT_BIT    3
#define FD_ACCEPT        (1 << FD_ACCEPT_BIT)
#define FD_CONNECT_BIT   4
#define FD_CONNECT       (1 << FD_CONNECT_BIT)
#define FD_CLOSE_BIT     5
#define FD_CLOSE         (1 << FD_CLOSE_BIT)typedef int SOCKET_HANDLE;typedef struct _FTP_Info
{char servIP[20];int  servPort;char userName[20];char userPassword[20];
} FTP_Info;int ftp_socket_connect(SOCKET_HANDLE socketHandle, const char *ipAddress, const int port);
SOCKET_HANDLE ftp_socket_create(void);
int ftp_socket_select(SOCKET_HANDLE socketHandle, int event, int secTime);
FTP_Ret ftp_socket_close(SOCKET_HANDLE socketHandle);
FTP_Ret ftp_socket_listen(SOCKET_HANDLE socketHandle, int maxListen);
int ftp_socket_accept(SOCKET_HANDLE socketHandle);
FTP_Ret
ftp_socket_bind_and_listen(SOCKET_HANDLE socketHandle, const char *ipAddress, const int port);DECLS_END#endif

ftp_socket.c: socket底层的处理

ftp_socket.c#include "unp.h"
#include "ftp_socket.h"int ftp_socket_connect(SOCKET_HANDLE socketHandle, const char *ipAddress, const int port)
{return_val_if_fail(socketHandle != INVALID_SOCKET, -1);return_val_if_fail(ipAddress != NULL, -1);struct sockaddr_in servAddr;bzero(&servAddr, sizeof(servAddr));servAddr.sin_family = AF_INET;servAddr.sin_port = htons(port);Inet_pton(AF_INET, ipAddress, &servAddr.sin_addr);return connect(socketHandle, (SA *)&servAddr, sizeof(servAddr));
}FTP_Ret
ftp_socket_bind_and_listen(SOCKET_HANDLE socketHandle, const char *ipAddress, const int port)
{return_val_if_fail(socketHandle != INVALID_SOCKET, FTP_RET_INVALID_PARAMS);return_val_if_fail(ipAddress != NULL, FTP_RET_INVALID_PARAMS);struct sockaddr_in servAddr;bzero(&servAddr, sizeof(servAddr));servAddr.sin_family = AF_INET;servAddr.sin_addr.s_addr = htonl(INADDR_ANY);servAddr.sin_port = htons(port);Bind(socketHandle, (SA *)&servAddr, sizeof(servAddr));Listen(socketHandle, LISTENQ);return FTP_RET_OK;
}FTP_Ret ftp_socket_listen(SOCKET_HANDLE socketHandle, int maxListen)
{return_val_if_fail(socketHandle != INVALID_SOCKET, FTP_RET_INVALID_PARAMS);Listen(socketHandle, maxListen);return FTP_RET_OK;
}int ftp_socket_accept(SOCKET_HANDLE socketHandle)
{return_val_if_fail(socketHandle != INVALID_SOCKET, FTP_RET_INVALID_PARAMS);return accept(socketHandle, NULL, NULL);
}SOCKET_HANDLE ftp_socket_create(void)
{return Socket(AF_INET, SOCK_STREAM, 0);
}int ftp_socket_select(SOCKET_HANDLE socketHandle, int event, int secTime)
{return_val_if_fail(socketHandle != INVALID_SOCKET, FTP_RET_INVALID_PARAMS);struct timeval timeValue;fd_set readSet, writeSet;FD_ZERO(&readSet);if ( (event & FD_ACCEPT) or (event & FD_READ) or (event & FD_CLOSE) ){FD_SET(socketHandle, &readSet);}FD_ZERO(&writeSet);if ( (event & FD_CONNECT) or (event & FD_WRITE) ){FD_SET(socketHandle, &writeSet);}timeValue.tv_sec = secTime;timeValue.tv_usec = secTime * 1000;return select(socketHandle + 1, &readSet, &writeSet, NULL, &timeValue);
}FTP_Ret ftp_socket_close(SOCKET_HANDLE socketHandle)
{return_val_if_fail(socketHandle != INVALID_SOCKET, FTP_RET_INVALID_PARAMS);close(socketHandle);socketHandle = INVALID_SOCKET;return FTP_RET_OK;
}

ftp.h: 只给出一个FTP进入点的接口,其他FTP操作都封装在ftp.c里面

ftp.h#include "ftp_socket.h"#ifndef FTP_H
#define FTP_HDECLS_BEGIN#define FTP_REPLY_SIZE 512 typedef enum _mode
{FTP_MODE_PASV,FTP_MODE_PORT
} FTP_trans_mode;typedef struct _FTP_obj
{SOCKET_HANDLE commandChannel;SOCKET_HANDLE dataChannel;unsigned int secTimeOut;int replyCode;char replyString[FTP_REPLY_SIZE];FTP_trans_mode transMode;
} FTP_Obj;typedef FTP_Ret (*FtpCommandFunc)(FTP_Obj *ftpObj, const char *command);FTP_Ret FTP_entry(const char *ipAddress, const int port);DECLS_END#endif

ftp.c : FTP核心代码,包含FTP的操作实现,这部分相对比较长:

ftp.c#include <curses.h>
#include "ftp.h"
#include "unp.h"#define FTP_PROMPT        "ftp> "
#define COMMAND_SIZE    256
#define MAX_PROMPT_SIZE 128
#define MAX_RECV_SIZE    1024 << 1static bool ftp_set_nonblock(SOCKET_HANDLE socketHandle)
{int flag = fcntl(socketHandle, F_GETFL);flag |= O_NONBLOCK;if (fcntl(socketHandle, F_SETFL, flag) == -1){return false;}return true;
}static int ftp_send_buffer(SOCKET_HANDLE socketHandle, const char *buffer, size_t size)
{return write(socketHandle, buffer, size);
}static FTP_Ret ftp_send_command(SOCKET_HANDLE socketHandle, const char *command)
{return_val_if_fail(socketHandle != INVALID_SOCKET, FTP_RET_INVALID_PARAMS);return_val_if_fail(command != NULL, FTP_RET_INVALID_PARAMS);char sendCommand[COMMAND_SIZE] = {0x00};sprintf(sendCommand, "%s\r\n", command);Writen(socketHandle, sendCommand, strlen(sendCommand));return FTP_RET_OK;
}static long
ftp_recv_command(SOCKET_HANDLE socketHandle, char *recvBuf, unsigned long recvMaxSize)
{return_val_if_fail(socketHandle != INVALID_SOCKET, -1);return_val_if_fail(recvBuf != NULL, -1);long recvSize = 0;long totalSize = 0;do{recvSize = recv(socketHandle, recvBuf + totalSize, recvMaxSize - totalSize, 0);totalSize += recvSize;} while (recvSize > 0);return totalSize;
}static FTP_Ret ftp_init_obj(FTP_Obj *ftpObj)
{return_val_if_fail(ftpObj != NULL, FTP_RET_INVALID_PARAMS);ftpObj->commandChannel = INVALID_SOCKET;ftpObj->dataChannel       = INVALID_SOCKET;ftpObj->secTimeOut       = 60;ftpObj->replyCode       = -1;ftpObj->transMode      = FTP_MODE_PASV;memset(ftpObj->replyString, 0x00, sizeof(ftpObj->replyString));return FTP_RET_OK;
}static FTP_Ret ftp_get_reply(FTP_Obj *ftpObj)
{return_val_if_fail(ftpObj != NULL, FTP_RET_INVALID_PARAMS);return_val_if_fail(ftpObj->commandChannel != INVALID_SOCKET, FTP_RET_FAIL);char recvBuf[MAX_RECV_SIZE] = {0x00};ftpObj->replyCode = -1;memset(ftpObj->replyString, 0x00, sizeof(ftpObj->replyString));while (ftp_socket_select(ftpObj->commandChannel, FD_READ, ftpObj->secTimeOut) > 0){ftp_set_nonblock(ftpObj->commandChannel);if (ftp_recv_command(ftpObj->commandChannel, recvBuf, MAX_RECV_SIZE) <= 0){fprintf(stderr, "Recv reply message failed.\n");return FTP_RET_FAIL;}else{printf("%s", recvBuf);strncpy(ftpObj->replyString, recvBuf, strlen(recvBuf));return FTP_RET_OK;}}return FTP_RET_FAIL;
}static FTP_Ret ftp_send_and_recv_reply(FTP_Obj *ftpObj, const char *command)
{return_val_if_fail(ftpObj != NULL, FTP_RET_INVALID_PARAMS);return_val_if_fail(command != NULL, FTP_RET_INVALID_PARAMS);ftp_send_command(ftpObj->commandChannel, command);memset(ftpObj->replyString, 0x00, sizeof(ftpObj->replyString));return ftp_get_reply(ftpObj);
}static FTP_Obj *ftp_connect_server(const char *ipAddress, const int port)
{return_val_if_fail(ipAddress != NULL, NULL);FTP_Obj *ftpObj = (FTP_Obj *)malloc(sizeof(FTP_Obj));return_val_if_fail(ftpObj != NULL, NULL);ftp_init_obj(ftpObj);ftpObj->commandChannel = ftp_socket_create();if (ftpObj->commandChannel == INVALID_SOCKET){fprintf(stderr, "creating socket failed.\n");goto error;}else{int ret = ftp_socket_connect(ftpObj->commandChannel, ipAddress, port);if (ret != 0){fprintf(stderr, "connect to %s failed.\n", ipAddress);goto error;}else{fprintf(stdout, "connected to %s.\n", ipAddress);if (ftp_get_reply(ftpObj) == FTP_RET_OK){return ftpObj;}else{goto error;}}}error:SAFE_FREE(ftpObj);return NULL;
}static void ftp_login_enter_name(char *userName, const int maxSize, const char *ipAddress)
{char enterNamePrompt[MAX_PROMPT_SIZE] = {0x00};sprintf(enterNamePrompt, "Name (%s): ", ipAddress);printf("%s", enterNamePrompt);Fgets(userName, maxSize, stdin);userName[strlen(userName) - 1] = '\0';
}static void ftp_login_enter_password(char *userPassword, const int maxSize)
{char enterPwPrompt[MAX_PROMPT_SIZE] = {0x00};sprintf(enterPwPrompt, "Password: ");printf("%s", enterPwPrompt);Fgets(userPassword, maxSize, stdin);userPassword[strlen(userPassword) - 1] = '\0';
}static FTP_Ret ftp_login(FTP_Obj *ftpObj, const char *ipAddress)
{return_val_if_fail(ftpObj != NULL, FTP_RET_INVALID_PARAMS);return_val_if_fail(ipAddress != NULL, FTP_RET_INVALID_PARAMS);char command[COMMAND_SIZE];char userName[20] = {0x00};char userPassword[20] = {0x00};ftp_login_enter_name(userName, 20, ipAddress);memset(command, 0x00, sizeof(command));sprintf(command, "USER %s", userName);if (ftp_send_and_recv_reply(ftpObj, command) == FTP_RET_OK){if (strncmp(ftpObj->replyString, "331", 3) != 0){return FTP_RET_FAIL;}ftp_login_enter_password(userPassword, 20);memset(command, 0x00, sizeof(command));sprintf(command, "PASS %s", userPassword);if (ftp_send_and_recv_reply(ftpObj, command) == FTP_RET_OK){if (strncmp(ftpObj->replyString, "230", 3) != 0){return FTP_RET_FAIL;}}}else{return FTP_RET_FAIL;}return FTP_RET_OK;
}static FTP_Ret ftp_syst(FTP_Obj *ftpObj, const char *command)
{return_val_if_fail(ftpObj != NULL, FTP_RET_INVALID_PARAMS);return ftp_send_and_recv_reply(ftpObj, "SYST");
}static FTP_Ret ftp_set_transfer_type(FTP_Obj *ftpObj, const char *command)
{return_val_if_fail(ftpObj != NULL, FTP_RET_INVALID_PARAMS);return ftp_send_and_recv_reply(ftpObj, command);
}static FTP_Ret ftp_set_transfer_mode(FTP_Obj *ftpObj, const char *command)
{return_val_if_fail(ftpObj != NULL, FTP_RET_INVALID_PARAMS);return ftp_send_and_recv_reply(ftpObj, command);
}static bool ftp_pasv(FTP_Obj *ftpObj)
{return_val_if_fail(ftpObj != NULL, false);char pasv[32] = {0x00};char hostAddr[16] = {0x00};unsigned int addr_1, addr_2, addr_3, addr_4, port_1, port_2;ftpObj->dataChannel = ftp_socket_create();if (ftp_send_and_recv_reply(ftpObj, "PASV") != FTP_RET_OK){return false;}strcpy(pasv, strchr(ftpObj->replyString, '(') );sscanf(pasv, "(%d, %d, %d, %d, %d, %d)", &addr_1, &addr_2, &addr_3, &addr_4, &port_1, &port_2);sprintf(hostAddr, "%d.%d.%d.%d", addr_1, addr_2, addr_3, addr_4);if (ftp_socket_connect(ftpObj->dataChannel, hostAddr, (port_1 << 8) | port_2) != 0){return false;}return true;
}#define UC(arg)    ( ( (int)arg) & 0xff)
static bool ftp_port(FTP_Obj *ftpObj)
{return_val_if_fail(ftpObj != NULL, false);char *addr, *port;char command[256] = {0x00};struct sockaddr_in dataAddr;size_t len = sizeof(dataAddr);if (getsockname(ftpObj->commandChannel, (struct sockaddr *)&dataAddr, &len) != 0){return false;}ftpObj->dataChannel = ftp_socket_create();if (ftpObj->dataChannel == INVALID_SOCKET){return false;}if (bind(ftpObj->dataChannel, (struct sockaddr *)&dataAddr, len) != 0){return false;}if (getsockname(ftpObj->dataChannel, (struct sockaddr *)&dataAddr, &len) != 0){return false;}if (ftp_socket_listen(ftpObj->dataChannel, 1) != 0){return false;}addr = (char *)&dataAddr.sin_addr;port = (char *)&dataAddr.sin_port;sprintf(command, "PORT %d, %d, %d, %d, %d, %d",UC(addr[0]), UC(addr[1]), UC(addr[2]), UC(addr[3]),UC(port[0]), UC(port[1]) );if (ftp_send_and_recv_reply(ftpObj, command) != FTP_RET_OK){return false;}return true;
}static bool ftp_init_data_channel(FTP_Obj *ftpObj)
{return_val_if_fail(ftpObj != NULL, false);if (ftpObj->dataChannel != INVALID_SOCKET){ftp_socket_close(ftpObj->dataChannel);}if (ftpObj->transMode == FTP_MODE_PASV){return ftp_pasv(ftpObj);}else{return ftp_port(ftpObj);}return false;
}static bool ftp_build_data_channel(FTP_Obj *ftpObj)
{return_val_if_fail(ftpObj != NULL, false);if (ftpObj->transMode == FTP_MODE_PASV){return true;}if (ftp_socket_select(ftpObj->dataChannel, FD_ACCEPT, ftpObj->secTimeOut) <= 0){return false;}SOCKET_HANDLE socketHandle = ftp_socket_accept(ftpObj->dataChannel);if (socketHandle == INVALID_SOCKET){return false;}else{ftp_socket_close(ftpObj->dataChannel);ftpObj->dataChannel = socketHandle;ftp_set_nonblock(ftpObj->dataChannel);    // set nonblockreturn true;}return false;
}#define MAX_RECV_DATA_SIZE 1024 * 100
static char* ftp_recv_data_channnel(FTP_Obj *ftpObj, const char *command)
{if (ftp_init_data_channel(ftpObj) != true){ftp_socket_close(ftpObj->dataChannel);return NULL;}if (ftp_send_and_recv_reply(ftpObj, command) != FTP_RET_OK){return NULL;}if (ftp_build_data_channel(ftpObj) != true){return NULL;}char *recvBuf = (char *)malloc(sizeof(char) * MAX_RECV_DATA_SIZE);if (recvBuf == NULL){return NULL;}memset(recvBuf, 0x00, MAX_RECV_DATA_SIZE);if (ftp_recv_command(ftpObj->dataChannel, recvBuf, MAX_RECV_DATA_SIZE) < 0){return NULL;}return recvBuf;
}static FTP_Ret ftp_list(FTP_Obj *ftpObj, const char *command)
{return_val_if_fail(ftpObj != NULL, FTP_RET_INVALID_PARAMS);return_val_if_fail(command != NULL, FTP_RET_INVALID_PARAMS);char *recvBuf = ftp_recv_data_channnel(ftpObj, command);if (recvBuf != NULL){printf("%s", recvBuf);SAFE_FREE(recvBuf);ftp_socket_close(ftpObj->dataChannel);if (ftp_get_reply(ftpObj) == FTP_RET_OK){return FTP_RET_OK;}}return FTP_RET_FAIL;
}static long ftp_get_file_size(const char *replyString)
{return_val_if_fail(replyString != NULL, -1);char sizeBuf[10] = {0x00};char *ptr = strchr(replyString, '(');int index;for (index = 0, ptr += 1; index < 10; ++index, ++ptr){if (*ptr != ' '){sizeBuf[index] = *ptr;}else{break;}}return atol(sizeBuf);
}static bool ftp_get_file_name(const char *replyString, char *fileName)
{return_val_if_fail(replyString != NULL, -1);char *ptr = strstr(replyString, "for");if (ptr != NULL){int index;// (ptr += 4) : ignore the "for " substringfor (index = 0, ptr += 4; *ptr != '\0'; ++ptr, ++index){if (*ptr != ' '){fileName[index] = *ptr;}else{return true;}}}return false;
}static FTP_Ret ftp_get_file(FTP_Obj *ftpObj, const char *command)
{return_val_if_fail(ftpObj != NULL, FTP_RET_INVALID_PARAMS);return_val_if_fail(command != NULL, FTP_RET_INVALID_PARAMS);char *recvBuf = ftp_recv_data_channnel(ftpObj, command);if (recvBuf != NULL){char fileName[256] = {0x00};long fileSize = ftp_get_file_size(ftpObj->replyString);if (ftp_get_file_name(ftpObj->replyString, fileName) == true){int fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IRGRP);if (fileSize != 0){long writeSize = write(fd, recvBuf, fileSize);if (writeSize != fileSize){return FTP_RET_FAIL;}}close(fd);}SAFE_FREE(recvBuf);ftp_socket_close(ftpObj->dataChannel);if (ftp_get_reply(ftpObj) == FTP_RET_OK){return FTP_RET_OK;}}return FTP_RET_FAIL;
}static bool ftp_put_file_name(const char *command, char *fileName)
{char *ptr = strchr(command, ' ');if (ptr != NULL){int index = 0;for (ptr += 1; *ptr != '\0'; ++index, ++ptr){fileName[index] = *ptr;}return true;}return false;
}static long ftp_put_file_size(const char *fileName)
{struct stat buf;if (stat(fileName, &buf) == -1){return -1;}return buf.st_size;
}static FTP_Ret ftp_put_file(FTP_Obj *ftpObj, const char *command)
{return_val_if_fail(ftpObj != NULL, FTP_RET_INVALID_PARAMS);return_val_if_fail(command != NULL, FTP_RET_INVALID_PARAMS);if (ftpObj->commandChannel == INVALID_SOCKET){return FTP_RET_FAIL;}if (ftp_init_data_channel(ftpObj) != true){ftp_socket_close(ftpObj->dataChannel);return FTP_RET_FAIL;}if (ftp_send_and_recv_reply(ftpObj, command) != FTP_RET_OK){return FTP_RET_FAIL;}if (ftp_build_data_channel(ftpObj) != true){return FTP_RET_FAIL;}char fileName[256] = {0x00};if (ftp_put_file_name(command, fileName) == true){long size = ftp_put_file_size(fileName);printf("----->put: %s: %ld\n", fileName, size);int fd = open(fileName, O_RDONLY);if (fd != -1){char *recvBuf = (char *)malloc(sizeof(char) * MAX_RECV_DATA_SIZE);if (recvBuf != NULL){ssize_t readSize = read(fd, recvBuf, size);if (readSize <= 0){return FTP_RET_FAIL;}if (ftp_send_buffer(ftpObj->dataChannel, recvBuf, readSize) != -1){close(fd);ftp_socket_close(ftpObj->dataChannel);}return ftp_get_reply(ftpObj);}}}return FTP_RET_FAIL;
}static FTP_Ret ftp_delete_file(FTP_Obj *ftpObj, const char *command)
{return_val_if_fail(ftpObj != NULL, FTP_RET_INVALID_PARAMS);return_val_if_fail(command != NULL, FTP_RET_INVALID_PARAMS);return ftp_send_and_recv_reply(ftpObj, command);
}static FTP_Ret ftp_make_directory(FTP_Obj *ftpObj, const char *command)
{return_val_if_fail(ftpObj != NULL, FTP_RET_INVALID_PARAMS);return_val_if_fail(command != NULL, FTP_RET_INVALID_PARAMS);return ftp_send_and_recv_reply(ftpObj, command);
}static FTP_Ret ftp_remove_directory(FTP_Obj *ftpObj, const char *command)
{return_val_if_fail(ftpObj != NULL, FTP_RET_INVALID_PARAMS);return_val_if_fail(command != NULL, FTP_RET_INVALID_PARAMS);return ftp_send_and_recv_reply(ftpObj, command);
}static FTP_Ret ftp_change_directory(FTP_Obj *ftpObj, const char *command)
{return_val_if_fail(ftpObj != NULL, FTP_RET_INVALID_PARAMS);return_val_if_fail(command != NULL, FTP_RET_INVALID_PARAMS);return ftp_send_and_recv_reply(ftpObj, command);
}static FTP_Ret ftp_pwd(FTP_Obj *ftpObj, const char *command)
{return_val_if_fail(ftpObj != NULL, FTP_RET_INVALID_PARAMS);return_val_if_fail(command != NULL, FTP_RET_INVALID_PARAMS);return ftp_send_and_recv_reply(ftpObj, "PWD");
}static FTP_Ret ftp_close(FTP_Obj *ftpObj, const char *command)
{return_val_if_fail(ftpObj != NULL, FTP_RET_INVALID_PARAMS);return_val_if_fail(command != NULL, FTP_RET_INVALID_PARAMS);if (ftpObj->commandChannel != INVALID_SOCKET){FTP_Ret ret = ftp_send_and_recv_reply(ftpObj, command);if (ret == FTP_RET_OK){ftp_socket_close(ftpObj->commandChannel);}else{return FTP_RET_FAIL;}}if (ftpObj->dataChannel != INVALID_SOCKET){ftp_socket_close(ftpObj->dataChannel);}SAFE_FREE(ftpObj);return FTP_RET_OK;
}static bool ftp_command_filter(const char *command, char *filter)
{int index = 0;for ( ; *command != '\0'; ++index, ++command){if (*command != ' '){filter[index] = *command;}else{return true;}}return false;
}static bool ftp_replay_command(char *sendCommand, const char *commandName)
{char temp[COMMAND_SIZE] = {0x00};char *ptr = strchr(sendCommand, ' ');if (ptr == NULL){strcpy(sendCommand, commandName);return true;}strcpy(temp, commandName);strcat(temp, ptr);if (strlen(temp) <= COMMAND_SIZE){strcpy(sendCommand, temp);return true;}return false;
}typedef struct _ftp_do_command
{char command[COMMAND_SIZE];FtpCommandFunc ftp_do_command;
} ftp_command_tag;const FtpCommandFunc ftp_command_func[] =
{ftp_list,ftp_list,ftp_pwd,ftp_change_directory,ftp_set_transfer_type,ftp_set_transfer_type,ftp_set_transfer_mode,ftp_get_file,ftp_put_file,ftp_delete_file,ftp_syst,ftp_make_directory,ftp_remove_directory,ftp_close,ftp_close,
};const char *command_name[] =
{"ls", "dir", "pwd", "cd", "ascii", "binary","passive", "get", "put", "delete", "system","mkdir", "rmdir", "quit", "bye",
};const char *replace_command[] =
{"LIST", "LIST", "PWD", "CWD", "TYPE A", "TYPE I","passive", "RETR", "STOR", "DELE", "SYST","MKD", "RMD", "QUIT", "QUIT",
};static int ftp_return_command_index(const char *command)
{int index;int number = sizeof(command_name) / sizeof(char *);for (index = 0; index < number; ++index){if (strcmp(command, command_name[index]) == 0){return index;}}return -1;
}FTP_Ret FTP_entry(const char *ipAddress, const int port)
{FTP_Obj *ftpObj = ftp_connect_server(ipAddress, port);if (ftpObj != NULL){ftp_login(ftpObj, ipAddress);ftp_syst(ftpObj, NULL);ftp_set_transfer_mode(ftpObj, "TYPE I");while (1){char enterCommand[256] = {0x00};Writen(1, FTP_PROMPT, sizeof(FTP_PROMPT));memset(enterCommand, 0x00, sizeof(enterCommand));Fgets(enterCommand, 256, stdin);enterCommand[strlen(enterCommand) - 1] = '\0';char filter[256] = {0x00};ftp_command_filter(enterCommand, filter);int index = ftp_return_command_index(filter);if (index >= 0){ftp_replay_command(enterCommand, replace_command[index]);printf("-------->%s\n", enterCommand);ftp_command_func[index](ftpObj, enterCommand);}if (strcmp(enterCommand, "QUIT") == 0){break;}else if (strcmp(enterCommand, "") == 0){continue;}}}return FTP_RET_OK;
}

main.c:

main.c#include "ftp.h"
#include "unp.h"#define DEBUG    0
#define PORT    21static void ftp_test(const char *ipAddress)
{FTP_entry(ipAddress, PORT);return;
}int main(int argc, char *argv[])
{if (argc != 2){fprintf(stderr, "Usage: ./ftp_client <IP>\n");return -1;}ftp_test(argv[1]);return 0;
}

Makefile:

MakefileCC=gcc
CFILES=main.c ftp.c ftp_socket.c
OBJ+=$(CFILES:.c=.o)
EXE=ftp_clientall:   $(EXE)
$(EXE)    :    $(OBJ) $(LIBFILES)$(CC) -Wall $(CFILES:.c=.o) -o $@ -lunp -lcursesclean:rm -f  *.o *.gdb $(EXE).SUFFIXES: .cpp  .c .o.c.o:$(CC) -Wall -o $*.o -c $(CCFLAGS) $*.c

END

原文地址:http://www.cnblogs.com/python_newbie/archive/2010/08/01/1789954.html

FTP客户端简单例程相关推荐

  1. android ftp客户端简单实现

    首先使用的是apache的commons-net-3.0.1.jar包点击下载 导入包后, //初始化FTPClint对象 FTPClient ftpClient = new FTPClient(); ...

  2. C++ 简单FTP客户端软件开发

    题目 简单FTP客户端软件开发(100分)网络环境中的一项基本应用就是将文件从一台计算机中复制到另一台可能相距很远的计算机中.而文件传送协议FTP是因特网上使用得最广泛的文件传送协议.FTP使用客户服 ...

  3. 计算机网络 简单FTP客户端软件的实现

    一.原理概述 1.1 FTP原理概述 文件传送协议FTP(File Transfer Protocol)是TCP/IP体系的一个重要协议,它采用Internet标准文件传输协议FTP的用户界面,向用户 ...

  4. Golang实现一个简单的FTP客户端

    使用Golang语言实现的一个简单的FTP客户端:Github源码:Golang实现一个简单的FTP客户端

  5. linux 下简单的ftp客户端程序

    该ftp的客服端是在linux下面写,涉及的东西也比较简单,如前ftp的简单介绍,知道ftp主要的工作流程架构,套接字的创建,还有就是字符串和字符的处理.使用的函数都是比较简单平常易见的,写的时候感觉 ...

  6. 简单vsftpd安装配置和 ftp客户端操作笔记

    #安装vsftpd yum install vsftpd #创建要登录ftp的本地用户 useradd -s /bin/false   用户名         #创建禁止ssh登录的用户 passwd ...

  7. 【RL-TCPnet网络教程】第37章 RL-TCPnet之FTP客户端

    第37章      RL-TCPnet之FTP客户端 本章节为大家讲解RL-TCPnet的FTP客户端应用,学习本章节前,务必要优先学习第35章的FTP基础知识.有了这些基础知识之后,再搞本章节会有事 ...

  8. 【RL-TCPnet网络教程】第37章 RL-TCPnet之FTP客户端

    第37章      RL-TCPnet之FTP客户端 本章节为大家讲解RL-TCPnet的FTP客户端应用,学习本章节前,务必要优先学习第35章的FTP基础知识.有了这些基础知识之后,再搞本章节会有事 ...

  9. 安装ftp连接linux服务器配置,Linux下FTP安装及配置(VSFTPD服务器安装配置、FTP客户端安装配置)...

    安装说明 安装环境:CentOS-6.3 安装方式:yum安装.rpm源码安装 软件:ftp-0.17-51.1.el6.x86_64.rpm 下载地址:http://pan.baidu.com/s/ ...

最新文章

  1. Linux命令行与shell脚本编程大全:第2版
  2. js 跨页面的全局变量
  3. JS拼凑方法之join
  4. 浅谈工业机器人的运动停止
  5. 2287. 【POJ Challenge】消失之物(数组递推\分治优化背包)
  6. 最高效的进(线)程间通信机制--eventfd
  7. asp.net ajax 怎么获取前端ul li_useEffect Hook 是如何工作的(前端需要懂的知识点)
  8. 【计算机网络】电路交换网络中,每条电路独占其经过的物理链路?
  9. php 返回的缓存数据,基于PHP输出缓存(output_buffering)的深入理解
  10. 禁用oracle的默认账户,Oracle EBS默认的账户
  11. Android中Activity出现与退出的自定义动画
  12. 【OUTLINE】使用Oracle Outline技术暂时锁定SQL的执行计划
  13. CentOS安装Nvidia驱动和CUDA
  14. 【游戏】基于 matlab GUI lanchester作战模拟设计【含Matlab源码 426期】
  15. 【归纳备忘】收集了一些神奇的BT种子磁力链接搜索网址
  16. 利用Adobe Photoshop 2020导入和批量输出论文中的图片
  17. 688. 骑士在棋盘上的概率(中等 动态规划)
  18. ESP8266 Blinker 小爱同学 本地控制 手机配网 四路开关 物联网 arduino编程详细注释
  19. 城市太美、生活步调太悠闲
  20. Springboot美食汇开放平台8ob70计算机毕业设计-课程设计-期末作业-毕设程序代做

热门文章

  1. uniApp 父与子 组件之间通信
  2. 客服助手,两大客服常用工具,值得收藏!
  3. java写弹力球游戏,用Qt5做的弹力球小游戏
  4. 详解数据存储芯片AT24C02的应用及编程
  5. Jupyter添加目录
  6. 手把手教你开通和使用融资融券账户!
  7. 满满的回忆,留在了潍柴汽车(我和小福的故事之七)
  8. 淘宝网店经营场所证明如何下载
  9. Python Urlencode URL编码与解码
  10. 9万元落地,市区开安静又舒服,A+价格B级享受