前提
在学习FTP客户端之前需要学会socket,FTP客户端与服务器之间的通讯就是使用socket的过程。
思路:
整个过程需要两个socket,一个用于与服务器端之间的操作,比如输入账号密码、读取文件大小或者删除文件之类的操作,另外一个socket用于接收文件内容、一个流;具体流程看下面的流程图。
流程图:

FTP命令:
| 命令 | 描述 |
|---|---|
| ABOR | 中断数据连接程序 |
| ACCT
|
系统特权帐号 |
| ALLO
|
为服务器上的文件存储器分配字节 |
| APPE
|
添加文件到服务器同名文件 |
| CDUP
|
改变服务器上的父目录 |
| CWD
|
改变服务器上的工作目录 |
| DELE
|
删除服务器上的指定文件 |
| HELP |
返回指定命令信息 |
| LIST
|
如果是文件名列出文件信息,如果是目录则列出文件列表 |
| MODE
|
传输模式(S=流模式,B=块模式,C=压缩模式) |
| MKD
|
在服务器上建立指定目录 |
| NLST
|
列出指定目录内容 |
| NOOP | 无动作,除了来自服务器上的承认 |
| PASS
|
系统登录密码 |
| PASV | 请求服务器等待数据连接 |
| PORT | IP 地址和两字节的端口 ID |
| PWD | 显示当前工作目录 |
| QUIT | 从 FTP 服务器上退出登录 |
| REIN | 重新初始化登录状态连接 |
| REST
|
由特定偏移量重启文件传递 |
| RETR
|
从服务器上找回(复制)文件 |
| RMD
|
在服务器上删除指定目录 |
| RNFR
|
对旧路径重命名 |
| RNTO
|
对新路径重命名 |
| SITE
|
由服务器提供的站点特殊参数 |
| SMNT
|
挂载指定文件结构 |
| STAT
|
在当前程序或目录上返回信息 |
| STOR
|
储存(复制)文件到服务器上 |
| STOU
|
储存文件到服务器名称上 |
| STRU
|
数据结构(F=文件,R=记录,P=页面) |
| SYST | 返回服务器使用的操作系统 |
| TYPE | 数据类型(A=ASCII,E=EBCDIC,I=binary) |
| USER
|
系统登录的用户名 |
FTP响应码:
| 响应代码 | 解释说明 |
|---|---|
| 110 | 新文件指示器上的重启标记 |
| 120 | 服务器准备就绪的时间(分钟数) |
| 125 | 打开数据连接,开始传输 |
| 150 | 打开连接 |
| 200 | 成功 |
| 202 | 命令没有执行 |
| 211 | 系统状态回复 |
| 212 | 目录状态回复 |
| 213 | 文件状态回复 |
| 214 | 帮助信息回复 |
| 215 | 系统类型回复 |
| 220 | 服务就绪 |
| 221 | 退出网络 |
| 225 | 打开数据连接 |
| 226 | 结束数据连接 |
| 227 | 进入被动模式(IP 地址、ID 端口) |
| 230 | 登录因特网 |
| 250 | 文件行为完成 |
| 257 | 路径名建立 |
| 331 | 要求密码 |
| 332 | 要求帐号 |
| 350 | 文件行为暂停 |
| 421 | 服务关闭 |
| 425 | 无法打开数据连接 |
| 426 | 结束连接 |
| 450 | 文件不可用 |
| 451 | 遇到本地错误 |
| 452 | 磁盘空间不足 |
| 500 | 无效命令 |
| 501 | 错误参数 |
| 502 | 命令没有执行 |
| 503 | 错误指令序列 |
| 504 | 无效命令参数 |
| 530 | 未登录网络 |
| 532 | 存储文件需要帐号 |
| 550 | 文件不可用 |
| 551 | 不知道的页类型 |
| 552 | 超过存储分配 |
| 553 | 文件名不允许 |
实际使用例子
int FTP_Updata_Check(tFTP_DATA *pFtpData_cmd, tFTP_DATA *pFtpData_data)
{
int sock_ftp_cmd, sock_ftp_data;
struct sockaddr_in ftp_cmd, ftp_data;
uint32_t version_num = 0;
memset(pFtpData_data, 0, sizeof(tFTP_DATA));
memset(pFtpData_cmd, 0, sizeof(tFTP_DATA));
if ((sock_ftp_cmd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("FTP: Socket_cmd application failed. . .");
return -1;
}
ftp_cmd.sin_family = AF_INET;
ftp_cmd.sin_port = htons(FTP_PORT_IND);
ftp_cmd.sin_addr.s_addr = inet_addr(FTP_IP_ADDR);
USER_INFO(ePRINTF_LV2, "FTP: Connect Server IP:%s:%d", FTP_IP_ADDR, FTP_PORT_IND);
if (connect(sock_ftp_cmd, (struct sockaddr *)&ftp_cmd, sizeof (ftp_cmd)) < 0)
{
printf("FTP: The server connection failed. . .");
closesocket(sock_ftp_cmd);
return -1;
}
read(sock_ftp_cmd, pFtpData_cmd->recevice_buf, sizeof(pFtpData_cmd->recevice_buf) - 1);
sprintf(pFtpData_cmd->send_buf, "USER %s\r\n", FTP_USERNAME);
write(sock_ftp_cmd, pFtpData_cmd->send_buf, strlen(pFtpData_cmd->send_buf));
read(sock_ftp_cmd, pFtpData_cmd->recevice_buf, sizeof(pFtpData_cmd->recevice_buf) - 1);
sprintf( pFtpData_cmd->send_buf, "PASS %s\r\n", FTP_PASS);
write(sock_ftp_cmd, pFtpData_cmd->send_buf, strlen(pFtpData_cmd->send_buf));
read(sock_ftp_cmd, pFtpData_cmd->recevice_buf, sizeof(pFtpData_cmd->recevice_buf) - 1);
sprintf( pFtpData_cmd->send_buf, "PASV\r\n");
write(sock_ftp_cmd, pFtpData_cmd->send_buf, strlen(pFtpData_cmd->send_buf));
read(sock_ftp_cmd, pFtpData_cmd->recevice_buf, sizeof(pFtpData_cmd->recevice_buf) - 1);
pFtpData_data->port = ftp_get_port(pFtpData_cmd->recevice_buf);
if ((sock_ftp_data = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("FTP: Socket_dat application failed. . .");
closesocket(sock_ftp_cmd);
return -1;
}
ftp_data.sin_family = AF_INET;
ftp_data.sin_port = htons(pFtpData_data->port);
ftp_data.sin_addr.s_addr = inet_addr(FTP_IP_ADDR);
if (connect(sock_ftp_data, (struct sockaddr *)&ftp_data, sizeof (ftp_data)) < 0)
{
printf("FTP: The server connection failed. . .");
closesocket(sock_ftp_data);
closesocket(sock_ftp_cmd);
return -1;
}
sprintf(pFtpData_cmd->send_buf, "SIZE abc.text\r\n");
write(sock_ftp_cmd, pFtpData_cmd->send_buf, strlen(pFtpData_cmd->send_buf));
memset(pFtpData_cmd->recevice_buf, 0, sizeof(pFtpData_cmd->recevice_buf));
read(sock_ftp_cmd, pFtpData_cmd->recevice_buf, sizeof(pFtpData_cmd->recevice_buf) - 1);
USER_INFO(ePRINTF_LV3, "FTP: <<<<%s", pFtpData_cmd->recevice_buf);
if(strstr(pFtpData_cmd->recevice_buf, "File not found"))
{
printf("FTP: There is no file. return");
closesocket(sock_ftp_data);
closesocket(sock_ftp_cmd);
return 0;
}
sprintf(pFtpData_cmd->send_buf, "RETR abc.text\r\n");
write(sock_ftp_cmd, pFtpData_cmd->send_buf, strlen(pFtpData_cmd->send_buf));
memset(pFtpData_cmd->recevice_buf, 0, sizeof(pFtpData_cmd->recevice_buf));
read(sock_ftp_cmd, pFtpData_cmd->recevice_buf, sizeof(pFtpData_cmd->recevice_buf) - 1);
if(strstr(pFtpData_cmd->recevice_buf, "File not found"))
{
printf("FTP: There is no file. return");
closesocket(sock_ftp_data);
closesocket(sock_ftp_cmd);
return 0;
}
read(sock_ftp_data, pFtpData_data->recevice_buf, sizeof(pFtpData_data->recevice_buf) - 1);//读文件内容
closesocket(sock_ftp_data);
closesocket(sock_ftp_cmd);
return 1;
}
