Linux/Unix 系统编程 — FTP客户端
尊重作者劳动成果,转载请注明出处,谢谢!
1. ftp.h
#ifndef ftp_H #define ftp_H #include "types.h" #include "socket.h" #ifdef __cplusplus extern "C" { #endif int ftp_login(const char *servIp, unsigned short port, const char *user, const char *password); boolean ftp_quit(int sockfd); boolean ftp_getCurrentDirectory(int sockfd, char *directory); boolean ftp_changDirectory(int sockfd, const char *directory); boolean ftp_changDirectoryUp(int sockfd); boolean ftp_createDirectory(int sockfd, const char *directory); boolean ftp_fileList(int sockfd); boolean ftp_download(int sockfd, const char *remoteFileName, const char *filePath); boolean ftp_upload(int sockfd, const char *remoteFileName, const char *filePath); #ifdef __cplusplus } #endif #endif
2. ftp.c
#include "ftp.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> static unsigned short strToHostAndPort(const char *str, char *host) { int addr[6]; sscanf(str, "%*[^(](%d,%d,%d,%d,%d,%d)", &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]); bzero(host, strlen(host)); sprintf(host, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); unsigned short port; port = addr[4] * 256 + addr[5]; return port; } static boolean recvAndCheck(int sockfd, const char *code) { char buf[1024] = {0}; int nrecv = recv(sockfd, buf, 1024, 0); if (nrecv <= 0) return False; printf("%s\n", buf); return strncmp(buf, code, 3) == 0 ? True : False; } static boolean ftp_sendCommandWithResult(int sockfd, const char *cmd, const char *arg, const char *code, char *result) { if (sockfd == INVALID_SOCKET) return False; char *cmdBuf = (char *)malloc(strlen(cmd) + strlen(arg) + 10); sprintf(cmdBuf, "%s %s\r\n", cmd, arg); int cmdBufSize = strlen(cmdBuf); int nsend = send(sockfd, cmdBuf, cmdBufSize, 0); free(cmdBuf); if (nsend != cmdBufSize) return False; char buf[1024] = {0}; int nrecv = recv(sockfd, buf, 1024, 0); printf("%s\n", buf); if (nrecv <= 0) return False; if (result != NULL) strcpy(result, buf); return strncmp(buf, code, 3) == 0 ? True : False; } static boolean ftp_sendCommand(int sockfd, const char *cmd, const char *arg, const char *code) { return ftp_sendCommandWithResult(sockfd, cmd, arg, code, NULL); } //使用被动模式,并返回数据端口的文件描述符 static int ftp_uesPasvMode(int sockfd) { if (sockfd == INVALID_SOCKET) return False; char buf[1024] = {0}; //227 Entering Passive Mode (192,168,1,100,191,160). if (!ftp_sendCommandWithResult(sockfd, "PASV", "", "227", buf)) return False; char data_host[32] = {0}; unsigned short data_port; data_port = strToHostAndPort(buf, data_host); return createTcpClient(data_host, data_port); } //ftp登录 int ftp_login(const char *servIp, unsigned short port, const char *user, const char *password) { int sockfd = createTcpClient(servIp, port); if (sockfd == INVALID_SOCKET) return -1; //220 (vsFTPd 3.0.3) if (!recvAndCheck(sockfd, "220")) { close(sockfd); return INVALID_SOCKET; } //331 Please specify the password. if (!ftp_sendCommand(sockfd, "USER", user, "331")) { close(sockfd); return INVALID_SOCKET; } //230 Login successful. if (!ftp_sendCommand(sockfd, "PASS", password, "230")) { close(sockfd); return INVALID_SOCKET; } //200 Switching to Binary mode. if (!ftp_sendCommand(sockfd, "TYPE", "I", "200")) { close(sockfd); return INVALID_SOCKET; } return sockfd; } //ftp注销 boolean ftp_quit(int sockfd) { if (sockfd == INVALID_SOCKET) return False; //221 Goodbye. if (!ftp_sendCommand(sockfd, "QUIT", "", "221")) return False; close(sockfd); return True; } //ftp获取当前工作目录 boolean ftp_getCurrentDirectory(int sockfd, char *directory) { if (sockfd == INVALID_SOCKET) return False; //257 "/root" is the current directory char buf[1024]; if (!ftp_sendCommandWithResult(sockfd, "PWD", "", "257", buf)) return False; int i = 0; char *ptr = buf + 5; while (*ptr != '"') { directory[i++] = *ptr; ptr++; } directory[i] = '\0'; return True; } //ftp更改当前工作目录 boolean ftp_changDirectory(int sockfd, const char *directory) { if (sockfd == INVALID_SOCKET) return False; //250 Directory successfully changed. return ftp_sendCommand(sockfd, "CWD", directory, "250"); } //ftp更改当前工作目录为上一级目录 boolean ftp_changDirectoryUp(int sockfd) { if (sockfd == INVALID_SOCKET) return False; //250 Directory successfully changed. return ftp_sendCommand(sockfd, "CDUP", "", "250"); } //ftp创建文件夹 boolean ftp_createDirectory(int sockfd, const char *directory) { if (sockfd == INVALID_SOCKET) return False; //257 "directory" created return ftp_sendCommand(sockfd, "MKD", directory, "257"); } //ftp文件列表 boolean ftp_fileList(int sockfd) { if (sockfd == INVALID_SOCKET) return False; int data_fd = ftp_uesPasvMode(sockfd); if (data_fd == INVALID_SOCKET) return False; //150 Here comes the directory listing. if (!ftp_sendCommand(sockfd, "LIST", "", "150")) { close(data_fd); return False; } int bufSize = 1024; char buf[1024] = {0}; int nrecv; while ((nrecv = recv(data_fd, buf, bufSize, 0)) > 0) { //drwx------ 2 0 0 0 Sep 24 05:51 123 //-rwx------ 1 0 0 34980 Aug 20 04:28 devserv //-rw------- 1 0 0 30 Aug 20 03:58 devserv.conf printf("%s\n", buf); } close(data_fd); //226 Directory send OK. return recvAndCheck(sockfd, "226"); } //ftp下载文件 boolean ftp_download(int sockfd, const char *remoteFileName, const char *filePath) { if (sockfd == INVALID_SOCKET) return False; int data_fd = ftp_uesPasvMode(sockfd); if (data_fd == INVALID_SOCKET) return False; //150 Opening BINARY mode data connection for "remoteFileName" (n bytes) if (!ftp_sendCommand(sockfd, "RETR", remoteFileName, "150")) { close(data_fd); return False; } int file_fd = open(filePath, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (file_fd < 0) { close(data_fd); return False; } int bufSize = 4096; char buf[4096]; int nread; while ((nread = recv(data_fd, buf, bufSize, 0)) > 0) { write(file_fd, buf, nread); } close(file_fd); close(data_fd); //226 Transfer complete. return recvAndCheck(sockfd, "226"); } //ftp上传文件 boolean ftp_upload(int sockfd, const char *remoteFileName, const char *filePath) { if (sockfd == INVALID_SOCKET) return False; if (access(filePath, F_OK) != 0) return False; int data_fd = ftp_uesPasvMode(sockfd); if (data_fd == INVALID_SOCKET) return False; //150 Ok to send data. if (!ftp_sendCommand(sockfd, "STOR", remoteFileName, "150")) { close(data_fd); return False; } int file_fd = open(filePath, O_RDONLY); if (file_fd < 0) { close(data_fd); return False; } int bufSize = 4096; char buf[4096]; int nread; while ((nread = read(file_fd, buf, bufSize)) > 0) { send(data_fd, buf, nread, 0); } close(file_fd); close(data_fd); //226 Transfer complete return recvAndCheck(sockfd, "226"); }