版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
概述
根本例实现从FTP server下载一个文件到本地,据需要,修改如下的宏定义则可运行。
#define FTP_USER_NAME “user” //FTP Server的用户名
#define FTP_USER_PSW “123456”//FTP Server的密码
#define FTP_IP “10.124.1.20” //FTP Server的IP
#define FTP_COMMAND_PORT 21 //端口号一般是21,不用修改
#define DWN_FILE_PATH “/test.c” //下载文件在FTP server的路径
#define SAVE_FILE_PATH “/home/user/test.c” //保存文件路径
源代码
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define FTP_USER_NAME "user"
#define FTP_USER_PSW "123456"
#define FTP_IP "10.124.1.20"
#define FTP_COMMAND_PORT 21
#define DWN_FILE_PATH "/test.c"
#define SAVE_FILE_PATH "/home/user/test.c"
/**********************************
*功能:TCP连接到指定IP和端口
*返回:-1 连接失败; 其它:文件描述符
*说明:
***********************************/
int tcp_sockConnect(char *ip,int port)
{
int sockfd;
struct sockaddr_in server_add;
memset(&server_add, 0, sizeof(struct sockaddr_in));
/*初始化socket*/
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == -1)
{
printf("create socket err\r\n");
return -1;
}
server_add.sin_family = AF_INET; /* IP protocol family.example:IPV4\IPV6*/
server_add.sin_port = htons(port); /* Port number*/
server_add.sin_addr.s_addr = inet_addr(ip); /* Internet address AF_INET*/
/*连接到服务器*/
if(connect(sockfd, (struct sockaddr *)&server_add, sizeof(server_add)) == -1)
{
printf("socket connect err\r\n");
return -1;
}
return sockfd;
}
/**********************************
*功能:FTP命令端口套字节连接,命令端口一般是21
*返回:-1 连接失败; 其它:文件描述符
*说明:
***********************************/
int ftp_commandSocketConnect(char *ip,int port)
{
char rcvBuf[512];
int commandSock;
int res;
/*TCP连接到命令端口*/
commandSock = tcp_sockConnect(ip,port);
if(res == -1)
{
printf("ftp command socket connect err\r\n");
return -1;
}
/*从服务端接收欢迎信息*/
if(recv(commandSock,rcvBuf,512,0) == -1)
{
printf("ftp receive welcome message err\r\n");
return -1;
}
sscanf(rcvBuf,"%d",&res);/*正常返回220响应码*/
if(res != 220)
{
printf("ftp welcome result err !=220\r\n");
close(commandSock);
return -1;
}
return commandSock;
}
/**********************************
*功能:客户端发送用户名和密码,登陆FTP服务器
*返回:-1 登陆失败;0 登陆成功
*说明:
***********************************/
int ftp_loginServer(int commandSock,char *userName,char *passWord)
{
char sendBuf[100];
char rcvBuf[100];
int res;
/*命令 "USER username\r\n"*/
sprintf(sendBuf,"USER %s\r\n",userName);
/*客户端发送用户名到服务器端 */
if(send(commandSock,sendBuf,strlen(sendBuf),0) == -1)
{
printf("ftp socket send err\r\n");
return -1;
}
/* 客户端接收服务器的响应码和信息,正常为 ”331 User name okay, need password.” */
if(recv(commandSock,rcvBuf,100,0) == -1)
{
printf("ftp recv login user message err\r\n");
return -1;
}
sscanf(rcvBuf,"%d",&res);
if(res != 331)
{
printf("ftp user command result err !=331\r\n");
return -1;
}
/*命令 "PASS password\r\n"*/
sprintf(sendBuf,"PASS %s\r\n",passWord);
/* 客户端发送密码到服务器端 */
if(send(commandSock,sendBuf,strlen(sendBuf),0) == -1)
{
printf("ftp socket send err");
return -1;
}
/* 客户端接收服务器的响应码和信息,正常为 ”230 User logged in, proceed.” */
if(recv(commandSock,rcvBuf,100,0) == -1)
{
printf("ftp recv login password message err\r\n");
return -1;
}
sscanf(rcvBuf,"%d",&res);
if(res != 230)
{
printf("ftp PASS command result err !=230\r\n");
return -1;
}
return 0;
}
/**********************************
*功能:被动模式下,接收FTP服务器返回的数据端口号,并TCP连接到数据端口
*返回:-1 连接数据端口失败,其它 返回数据端口的文件描述符
*参数:commandSock 命令sock描述符
*说明:
***********************************/
int ftp_dataSocketConnect(int commandSock)
{
char sendBuf[100];
char rcvBuf[100];
int dataSock;
int rcvAddBuf[6];/*接收到的IP和端口数据*/
char addStr[20];/*IP地址字符串格式*/
int res;
/*命令 "PASV\r\n"*/
sprintf(sendBuf,"PASV\r\n");
/* 客户端发送密码到服务器端 */
if(send(commandSock,sendBuf,strlen(sendBuf),0) == -1)
{
printf("ftp socket send err\r\n");
return -1;
}
/*客户端接收服务器的响应码和新开的端口号, *
正常为 ”227 Entering passive mode (<h1,h2,h3,h4,p1,p2>)” */
if(recv(commandSock,rcvBuf,100,0) == -1)
{
printf("ftp recv login password message err\r\n");
return -1;
}
sscanf(rcvBuf,"%d",&res);
if(res != 227)
{
printf("ftp PASV command result err !=227\r\n");
return -1;
}
/*从返回的消息中提取数据通道的IP和Port*/
sscanf(rcvBuf,"%*[^(](%d,%d,%d,%d,%d,%d)",&rcvAddBuf[0],&rcvAddBuf[1],&rcvAddBuf[2]\
,&rcvAddBuf[3],&rcvAddBuf[4],&rcvAddBuf[5]);
sprintf(addStr,"%d.%d.%d.%d",rcvAddBuf[0],rcvAddBuf[1],rcvAddBuf[2],rcvAddBuf[3]);
/*连接到数据端口*/
dataSock = tcp_sockConnect(addStr,rcvAddBuf[4]*256+rcvAddBuf[5]);
if(dataSock == -1)
{
printf("ftp connect data prot err\r\n");
return -1;
}
return dataSock;
}
/**********************************
*功能:从FTP服务器下载文件
*返回:
*参数:
*说明:
***********************************/
int ftp_downloadFile(int commandSock,int dataSock,char *downPath,char *savePath)
{
char sendBuf[100];
char rcvBuf[100];
int rcvLength;
FILE *fp = NULL;
int res;
/* 命令 ”RETR filename\r\n” */
sprintf(sendBuf,"RETR %s\r\n",downPath);
/* 客户端发送下载命令到服务器端 */
if(send(commandSock,sendBuf,strlen(sendBuf),0) == -1)
{
printf("ftp socket send err\r\n");
return -1;
}
/* 客户端接收服务器的响应码和信息,正常为 ”150 Opening data connection.” */
if(recv(commandSock,rcvBuf,100,0) == -1)
{
printf("ftp recv login password message err\r\n");
return -1;
}
sscanf(rcvBuf,"%d",&res);
if(res != 150)
{
printf("ftp RETR command result err !=150\r\n");
return -1;
}
/* 客户端创建文件 */
fp = fopen(savePath,"a+");
if(fp == NULL)
{
printf("save file open err\r\n");
return -1;
}
while(1)
{
/* 客户端通过数据连接 从服务器接收文件内容 */
rcvLength = recv(dataSock,rcvBuf,100,0);
if(rcvLength == 100)
{
/* 客户端写文件 */
fwrite(rcvBuf,1,rcvLength,fp);
}
else
{
break;
}
}
/* 客户端接收服务器的响应码和信息,正常为 ”226 Successfully transferred ” */
if(recv(commandSock,rcvBuf,100,0) == -1)
{
printf("ftp recv download command err\r\n");
return -1;
}
sscanf(rcvBuf,"%d",&res);
if(res != 226)
{
printf("ftp RETR download result err !=226\r\n");
return -1;
}
/* 客户端关闭文件 */
fclose(fp);
return 0;
}
/**********************************
*功能:退出FTP
*说明:
***********************************/
int ftp_quit(int commandSock)
{
char sendBuf[100];
char rcvBuf[100];
int res;
/* 命令 ”RETR filename\r\n” */
sprintf(sendBuf,"QUIT\r\n");
/* 客户端发送下载命令到服务器端 */
if(send(commandSock,sendBuf,strlen(sendBuf),0) == -1)
{
printf("ftp socket send err\r\n");
return -1;
}
/* 客户端接收服务器的响应码,正常为 ”200 Closes connection.” */
if(recv(commandSock,rcvBuf,100,0) == -1)
{
printf("ftp recv login password message err\r\n");
return -1;
}
if(res != 221)
{
printf("ftp QUIT command result err !=221\r\n");
return -1;
}
return 0;
}
int main(int argc,char *argv[])
{
int commandSock;/*命令端口socket文件描述符*/
int dataSock;/*FTP的数据端口*/
int res;
printf("main start\r\n");
/*客户端和 FTP 服务器建立 Socket 连接*/
commandSock = ftp_commandSocketConnect(FTP_IP,FTP_COMMAND_PORT);
if(commandSock == -1)
{
printf("ftp connect command socket err\r\n");
close(commandSock);
return -1;
}
printf("connect to command socket\r\n");
/*向服务器发送 USER、PASS 命令登录 FTP 服务器*/
res = ftp_loginServer(commandSock,FTP_USER_NAME,FTP_USER_PSW);
if(res == -1)
{
printf("ftp login server err\r\n");
close(commandSock);
return -1;
}
printf("log server sucess\r\n");
/*使用 PASV 命令得到服务器监听的端口号,建立数据连接*/
dataSock = ftp_dataSocketConnect(commandSock);
if(dataSock == -1)
{
printf("ftp data socket connect err\r\n");
close(commandSock);
return -1;
}
printf("connect data socket\r\n");
/*使用 RETR 命令下载文件*/
res = ftp_downloadFile(commandSock,dataSock,DWN_FILE_PATH,SAVE_FILE_PATH);
if(res == -1)
{
printf("ftp download file err\r\n");
close(commandSock);
close(dataSock);
return -1;
}
close(dataSock);
printf("download file ok\r\n");
/*退出FTP*/
res = ftp_quit(commandSock);
if(res == -1)
{
printf("ftp quit err\r\n");
close(commandSock);
return -1;
}
close(commandSock);
printf("ftp test over\r\n");
return 0;
}