Apr 13

myftp: 一个linux下简单的ftp客户端实现 不指定

felix021 @ 2009-4-13 17:24 [IT » 网络] 评论(3) , 引用(0) , 阅读(11135) | Via 本站原创 | |
因为网络程序设计课程要求做一个扩展型的作业,其中一个选项是ftp client。于是我就选了这个。
做完以后发现其实不难,而最难的地方,在于了解FTP协议的工作过程。
下面随便闲扯一点东西吧。

在网络上,经常遇到的应用层协议包括HTTP,FTP,SMTP,POP3,都使用TCP协议连接,感觉挺像的。

HTTP协议显然是最常见的,在客户端和服务器之间只有一条连接,既传输控制命令(HTTP头),也传输数据(HTTP实体)
因此在编写动态网页脚本的时候,一定要先输出header,然后才输出HTML代码。

FTP协议则采用两条连接,一条控制连接,一条数据连接。
控制连接用于传输控制命令,始终保持连接,直到客户端发出QUIT命令结束连接;
数据连接在需要传输数据的时候打开(发起端可以是客户端也可以是服务器),传输完毕后就断开。

FTP的数据连接有两种模式,一种是主动模式,一种是被动模式(PASV, Passive Mode)。
采用主动模式时,客户端监听一个本地端口,由服务器发起连接传输数据;
而采用被动模式时,则是由服务器打开一个端口,客户端发起连接接收数据。

下面我用telnet来模拟一个FTP客户端连接、登陆、使用被动模式传输文件并退出的完整过程:
在我的机器上,环境是Ubuntu 8.10 + vsftpd (@ Port 21)
约定一下格式:无特殊前缀的行是telnet输出的
$ 开头的行表示输入命令,<- 开头的行表示是收到的消息,
-> 开头的行表示是手工输入的消息,//开头的行是felix写的说明
//打开一个terminal,windows下打开命令提示符也是一样的,我们暂且称其为tty1
$ telnet localhost 21
Trying 127.0.0.1...
Connected to felix021-laptop.
Escape character is '^]'.
<- 220 Welcome to felix's FTP service.
//到这里可以看到,telnet已经连接到localhost的21号端口,服务器返回一个消息
//消息的格式是 220 ooxx,220大概表示一切OK,你可以开始登录了
//而ooxx则是一个简单的消息,是可以由管理员修改配置的
//注意:可能服务器会返回多行220消息
-> USER ooxx
<- 331 Please specify the password.
//说明用户名OK,等你输入密码
-> PASS xxoo
//故意输入一个错误的密码
<- 530 Login incorrect.
// 小样,密码错了就不让你登录,重新来
-> USER ooxx
<- 331 Please specify the password.
-> PASS ooxx
<- 230 login successful.
// OK,登上去了
-> PWD
257 "/home/ooxx"
// 当前我们在服务器的 /home/ooxx 目录下,下面我们看看这个目录下面有什么
// 因为目录的内容属于数据连接的,所以需要进入被动模式
-> PASV
<- 227 Entering Passive Mode (127,0,0,1,160,231)
//注意,服务器返回了6个[用逗号分隔的]数字
//前四个数字很容易认出吧?127.0.0.1,就是IP地址
//后面俩呢?就是端口号了,计算方法是 160 * 256 + 231 = 41191
-> LIST
//现在被阻塞了,因为服务器等着你连接它的41191端口接数据呢

//现在打开一个新的terminal,我们暂且称其为tty2
//@ tty2
$ telnet localhost 41191
Trying 127.0.0.1...
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
//哎呀不好意思,我动作太慢了,服务器等不及了,
//下面回到tty1,重来
//@ tty1
-> PASV
<- 227 Entering Passive Mode (127,0,0,1,73,55)
//PORT = 18743
-> LIST
//阻塞了,来,我们到tty2看看
//@ tty2
$ telnet localhost 18743
Trying 127.0.0.1...
Connected to felix021-laptop.
Escape character is '^]'.
<- drwxr-xr-x    2 1001     1001         4096 Apr 10 16:55 1"2
<- lrwxrwxrwx    1 1001     1001           26 Apr 10 06:09 Examples -> /usr/share/example-content
<- -rw-r--r--    1 1001     1001         4744 Apr 10 08:49 main.cpp
<- drwxr-xr-x    2 1001     1001         4096 Apr 10 07:58 ooxx
<- -rw-r--r--    1 1001     1001         2647 Apr 12 07:48 tags
Connection closed by foreign host.
//哗地一下刷过去这么多东西,不过稍微看一下,就会明白的吧:)
//咱再回到tty1看看
//@ tty1
<- 150 Here comes the directory listing.
<- 226 Directory send OK.
-> SIZE tags
//看看tags这个文件有多大
<-213 2647
//嗯,2647个字节,很好,这下我们可以下载文件了
//还是用被动模式(每次传输数据都要重新设置传输方式)
-> PASV
<- 227 Entering Passive Mode (127,0,0,1,34,112)
//PORT = 8816
-> RETR tags
//阻塞了,我们切换到tty2,来看看tags文件的内容是啥
//@ tty2
$ telnet localhost 8816
Trying 127.0.0.1...
Connected to felix021-laptop.
Escape character is '^]'.
<- ooxx ooxx ooxx ooxx
Connection closed by foreign host.
//好吧,我承认tags文件的内容不应该只有这么几个ooxx,不过它太长了,放在这里影响阅读不是~
// @ tty1
<- 150 Opening BINARY mode data connection for tags (2647 bytes).
<- 226 File send OK.
-> QUIT
<- 221 Goodbye.
//byebye~

好了,以上就是ftp客户端以被动模式向服务器请求一个文件的全过程。
主动模式稍稍有点不同,在需要传输数据的时候,需要先建立一个socket监听本地的某个端口P
计算出a, b满足P = a * 256 + b,然后使用PORT命令,后面跟上类似127,0,0,1,a,b的地址信息
然后使用TYPE I命令设置传输模式为BINARY(默认为ASCII)。
由于不能用telnet监听端口,所以主动模式的就不能使用telnet模拟了。

注意,由于ftp服务器程序的不同,输出的提示字符格式可能不同,但是状态码一定会按照RFC标准给出的。

下面附上我自己写的ftp client吧。仅供参考:因为只完成了PASV模式,能对付我机器上的vsftp,不能保证通用性=.=
p.s. 注意一点:在程序中编写需要传输给服务器的命令时,命令结尾必须加上一个\r\n (回车换行) 表示这是一行命令的结束。
再p.s. 我很不希望这个东西会被别人当作大作业交给老师。
@2009-06-02
再再p.s. 已经出了跨平台可编译版本哦,详见 myftp跨平台版本
下载文件 (已下载 1507 次)


最后:如果你要自己写一个客户端,并且想要实现更多命令,你可以使用 ftp -d localhost 来连接服务器
-d表示debug模式,所有在发送和接受到的控制命令都会显示出来,这样你就能看到你要实现的功能需要什么命令。
linux和windows下的ftp都支持-d参数。



欢迎扫码关注:




转载请注明出自 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: https://www.felix021.com/blog/feed.php
Tags: , ,
hanf
2010-11-21 20:50
非常好!!
hhe
2009-5-14 08:43
挺好的,顶下
felix021 回复于 2009-5-14 11:33
:)
xxx
2009-4-15 18:22
good article,thank you.
分页: 1/1 第一页 1 最后页
发表评论
表情
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
打开HTML
打开UBB
打开表情
隐藏
记住我
昵称   密码   *非必须
网址   电邮   [注册]