代码来源于网络,记录下,方便日后使用(适用于Linux平台)
/*使用FTP协议获取服务器上的文件(Passive方式)
1 在客户端创建一个SOCK_STREAM类型的套接字,并与FTP服务器端的21号命令端口连接(因为FTP服务器的21号端口在侦听);
2 再创建一个SOCK_STREAM类型的数据套接字,准备与FTP服务器端的数据端口进行通信(因为是Passive方式,所以服务器端的数据端口不是20号了)
3 发送用户名、密码到21号命令端口
4 发送PASV,从返回的字符串里取出的服务器上的数据端口号,然后客户端通过connect与该端口进行连接(此时服务器端的数据端口在侦听)
5 然后客户端就可以通过这两个套接字与服务器端进行通信了
使用FTP协议获取服务器上的文件(Port方式)
1 在客户端创建一个SOCK_STREAM类型的套接字,并与FTP服务器端的21号命令端口连接(因为FTP服务器的21号端口在侦听);
2 再创建一个SOCK_STREAM类型的数据套接字,准备与FTP服务器端的数据端口进行通信(因为是Port方式,所以服务器端的数据端口是20号)
3 绑定本地地址和数据套接字,然后就侦听,并等待服务器来连接(此时客户端的数据套接字要listen和accept)
3 发送用户名、密码到21号命令端口
4 发送PORT,等待服务器的数据端口来连接
5 连接成功后,客户端就可以通过这两个套接字与服务器端进行通信了
我这个程序是在linux下运行的;
在我的程序中:用户名是leetow,口令是leetow,FTP服务器的IP是192.168.1.90;
程序运行格式:程序名 要下载的文件名
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <strings.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <netdb.h>
#define FTP_SERVER "192.168.1.90"
int main(int argc,char* argv[])
{
int sk_data,sk_ctrl; //客户端的两个套接字,分别与服务器端的数据端口、命令端口端口进行通信
struct sockaddr_in addr_data,addr_ctrl; //服务器的两个地址,分别与客户端的数据端口、命令端口端口进行通信
struct in_addr inp;
//我这里的用户名是leetow,口令是leetow
char bufrecv[100],user[]="USER leetow\r\n",passwd[]="PASS leetow\r\n",pasv[]="PASV\r\n";
char size[30]="SIZE ",type[]="TYPE A\r\n",download[30]="RETR ",quit[100]="QUIT\r\n",line_end[]="\r\n";
char filebuf[50000],str[100]; //文件缓冲区
int lensnd,lenrecv,err;
int a1,a2,a3,a4,p1,p2;//从服务器返回的地址和端口
FILE *fp;
int len;
//获得文件名
if(argc!=2)
{
printf("Usage:%s filename \n", argv[0]);
return -1;
}
//补齐文件大小与下载文件的命令
strcat(size,argv[1]);
strcat(size,line_end);
strcat(download,argv[1]);
strcat(download,line_end);
//create two socket for SOCK_STREAM
sk_data=socket(AF_INET,SOCK_STREAM,0);
sk_ctrl=socket(AF_INET,SOCK_STREAM,0);
if(sk_data<0 )
{
perror("creat socket sk_data error");
return -1;
}
if(sk_ctrl < 0 )
{
perror("creat socket sk_ctrl error");
close(sk_data);
return -1;
}
//与服务器上的21号端口连接
bzero(&addr_ctrl,sizeof(struct sockaddr_in));
inet_aton(FTP_SERVER, &inp); //服务器IP地址
addr_ctrl.sin_family=AF_INET;
addr_ctrl.sin_addr=inp;
addr_ctrl.sin_port=htons(21); //FTP命令端口
//connect to server
err=connect(sk_ctrl,(struct sockaddr*)&addr_ctrl,sizeof(struct sockaddr));
if(-1==err)
{
perror("connect 21 error");
close(sk_data);
close(sk_ctrl);
return -1;
}
//输出服务器端的连接成功的信息
bzero(bufrecv,100);
lenrecv=recv(sk_ctrl,bufrecv,100,0);
if(lenrecv>0)
{
printf("connect 21 successfully:%s\n",bufrecv);
}
//发送用户名
lensnd=send(sk_ctrl,user,strlen(user),0);
if(lensnd>0)
{
bzero(bufrecv,100);
recv(sk_ctrl,bufrecv,100,0);
printf("user name:%s\n",bufrecv);
}
//发送口令
lensnd=send(sk_ctrl,passwd,strlen(passwd),0);
if(lensnd>0)
{
bzero(bufrecv,100);
recv(sk_ctrl,bufrecv,100,0);
printf("password:%s\n",bufrecv);
}
//PASV
lensnd=send(sk_ctrl,pasv,strlen(pasv),0);
if(lensnd>0)
{
bzero(bufrecv,100);
recv(sk_ctrl,bufrecv,100,0);
printf("pasv:%s\n",bufrecv);
sscanf(bufrecv,"%*[^(]%[^)]",str); //字符串中从"("开始一直到")"之间的字符存到str中,包括"("
sscanf(str,"(%d,%d,%d,%d,%d,%d",&a1,&a2,&a3,&a4,&p1,&p2);
printf("p1,p2=%d,%d\n",p1,p2);
printf("p1*256+p2=%d\n",p1*256+p2);
}
//指定服务器的数据端口
bzero(&addr_data,sizeof(struct sockaddr_in));
inet_aton(FTP_SERVER, &inp); //服务器IP地址
addr_data.sin_family=AF_INET;
addr_data.sin_addr=inp;
addr_data.sin_port=htons(p1*256+p2);
err=connect(sk_data,(struct sockaddr*)&addr_data,sizeof(struct sockaddr));
if(-1==err)
{
perror("connect 20 error");
close(sk_data);
close(sk_ctrl);
return -1;
}
//获得文件大小
lensnd=send(sk_ctrl,size,strlen(size),0);
if(lensnd>0)
{
bzero(bufrecv,100);
recv(sk_ctrl,bufrecv,100,0);
printf("sz:%s\n",bufrecv);
sscanf(bufrecv,"%d %d",&a1,&len);
printf("a1,len=%d,%d\n",a1,len);
}
//从服务器上获得文件
lensnd=send(sk_ctrl,download,strlen(download),0);
if(lensnd>0)
{
bzero(bufrecv,100);
recv(sk_ctrl,bufrecv,100,0);
printf("get file:%s\n",bufrecv);
}
//本地建文件并写入数据
fp=fopen(argv[1],"w");
if(NULL==fp)
{
printf("fopen error:\n");
close(sk_data);
close(sk_ctrl);
return -1;
}
lenrecv=recv(sk_data,filebuf,len,0);
if(lenrecv>0)
{
fwrite(filebuf,len,1,fp);
fclose(fp);
}
//退出
lensnd=send(sk_ctrl,quit,strlen(quit),0);
if(lensnd>0)
{
bzero(bufrecv,100);
recv(sk_ctrl,bufrecv,100,0);
printf("quit:%s\n",bufrecv);
printf("send qexit successful\n");
}
close(sk_data);
close(sk_ctrl);
return 0;
}
Makefile
#CROSS = arm-hisiv100nptl-linux-
CXX = $(CROSS)g++
RM=rm -f
CFLAGS = -Wall -Os -DLINUX
ALL=a
all: $(ALL)
a: a.cpp
$(CXX) $(CFLAGS) -o $@ $^
clean:
$(RM) *.o $(ALL)
运行
[zcm@ftp #49]$./a a.txt
connect 21 successfully:220 Microsoft FTP Service
user name:331 Password required for zcm.
password:230 User logged in.
pasv:227 Entering Passive Mode (192,168,1,90,143,39).
p1,p2=143,39
p1*256+p2=36647
sz:213 80
a1,len=213,80
get file:125 Data connection already open; Transfer starting.
quit:226 Transfer complete.
send qexit successful