第3章 因特网客户端编程
3.1 文件传输
3.1.1 文件传输协议
文件传输协议(File Transfer Protocol, FTP)
工作流程如下。
1.客户端连接远程主机上的 FTP 服务器。
2.客户端输入用户名和密码(或“anonymous”和电子邮件地址 )。
3.客户端进行各种文件传输和信息查询操作。
4.客户端从远程 FTP 服务器退出,结束传输。
当然,这只是一般情况下的流程。有时,由于网络两边计算机的崩溃或网络的问题,会导致整个传输在完成之前就中断。 如果客户端超过 15 分钟(900 秒) 还没有响应, FTP 连接就会超时并中断。
在底层, FTP 只使用 TCP(见第 2 章),而不使用 UDP。 另外, 可以将 FTP 看作客户端/服务器编程中的特殊情况。 因为这里的客户端和服务器都使用两个套接字来通信:一个是控制和命令端口(21 号端口),另一个是数据端口(有时是 20 号端口)
说“有时”是因为 FTP 有两种模式:主动和被动。只有在主动模式下服务器才使用数据端口。在服务器把 20 号端口设置为数据端口后,它“主动”连接客户端的数据端口。而在被动模式下,服务器只是告诉客户端随机的数据端口号,客户端必须主动建立数据连接。在这种模式下, FTP 服务器在建立数据连接时是“被动”的。最后,现在已经有了一种扩展的被动模式来支持第 6 版本的因特网协议(IPv6)地址
3.1.2 Python 和 FTP
流程:
1.连接到服务器。
2.登录。
3.发出服务请求(希望能得到响应)。
4.退出。
Pytho 伪代码:
from ftplib import FTP
f = FTP('some.ftp.server')
f.login('anonymous', 'your@email.address')
:
f.quit()
3.1.3 ftplib.FTP 类的方法
FTP 对象的方法
方 法 | 描 述 |
---|---|
login(user=’anonymous’,passwd=”, acct=”) | 登录 FTP 服务器,所有参数都是可选的 |
pwd() | 获得当前工作目录 |
cwd(path) | 把当前工作目录设置为 path 所示的路径 |
dir ([path[,…[,cb]]) | 显示 path 目录里的内容,可选的参数 cb 是一个回调函数,会传递给 retrlines()方法 |
nlst ([path[,…]) | 与 dir()类似, 但返回一个文件名列表,而不是显示这些文件名 |
retrlines(cmd [, cb]) | 给定 FTP命令(如“RETR filename”),用于下载文本文件。可选的回调函数 cb 用于处理文件的每一行 |
retrbinary(cmd,cb[,bs=8192[, ra]]) | 与 retrlines()类似,只是这个指令处理二进制文件。回调函数 cb 用于处理每一块(块大小默认为 8KB)下载的数据 |
storlines(cmd, f) | 给定 FTP 命令(如“STOR filename”),用来上传文本文件。要给定一个文件对象 f |
storbinary(cmd, f[,bs=8192]) | 与 storlines()类似,只是这个指令处理二进制文件。要给定一个文件对象 f,上传块大小 bs 默认为 8KB |
rename(old, new) | 把远程文件 old 重命名为 new |
delete(path) | 删除位于 path 的远程文件 |
mkd(directory) | 创建远程目录 |
rmd(directory) | 删除远程目录 |
quit() | 关闭连接并退出 |
关于 FTP 对象的更多信息,请参阅
https://docs.python.org/3/library/ftplib.html
3.1.4 交互式 FTP 示例
>>> from ftplib import FTP
>>> f = FTP('ftp.python.org')
>>> f.login('anonymous', 'guido@python.org')
'230 Guest login ok, access restrictions apply.'
>>> f.dir()
total 38
drwxrwxr-x 10 1075 4127 512 May 17 2000 .
drwxrwxr-x 10 1075 4127 512 May 17 2000 ..
drwxr-xr-x 3 root wheel 512 May 19 1998 bin
drwxr-sr-x 3 root 1400 512 Jun 9 1997 dev
drwxr-xr-x 3 root wheel 512 May 19 1998 etc
lrwxrwxrwx 1 root bin 7 Jun 29 1999 lib -> usr/lib
-r--r--r-- 1 guido 4127 52 Mar 24 2000 motd
drwxrwsr-x 8 1122 4127 512 May 17 2000 pub
drwxr-xr-x 5 root wheel 512 May 19 1998 usr
>>> f.retrlines('RETR motd')
Sun Microsystems Inc. SunOS 5.6 Generic August 1997
'226 Transfer complete.
>>> f.quit()
'221 Goodbye.'
3.1.5 客户端 FTP 程序示例
import ftplib
import os
import socket
# 链接国内好像访问不了
HOST = 'ftp.mozilla.org'
DIRN = 'pub/mozilla.org/webtools'
FILE = 'bugzilla-LATEST.tar.gz'
def main():
try:
# 创建一个 FTP 对象,尝试连接到 FTP 服务器
f = ftplib.FTP(HOST)
except (socket.error, socket.gaierror) as e:
print('ERROR: cannot reach "%s"' % HOST)
return
print('***Connected to host "%s"' % HOST)
try:
# 用“anonymous”登录
f.login()
except ftplib.error_perm:
print('ERROR: cannot login anonymously')
f.quit()
return
print('*** Logged in as "anonymous"')
try:
# 转到发布目录
f.cwd(DIRN)
except ftplib.error_perm:
print('ERROR: cannot CD to "%s"' % DIRN)
f.quit()
return
print('*** Changed to "%s" folder' % DIRN)
try:
# 下载文件
f.retrbinary('RETR %s' % FILE, open(FILE, 'wb').write)
except ftplib.error_perm:
print('ERROR: cannot read file "%s"' % FILE)
os.unlink(FILE)
else:
print('*** Downloaded "%s" to CWD' % FILE)
f.quit()
if __name__ == '__main__':
main()
3.2 网络新闻
3.2.1 Usenet 与新闻组
Usenet 新闻系统是一个全球存档的“电子公告板”。各种主题的新闻组一应俱全,从诗歌到政治,从自然语言学到计算机语言,从软件到硬件,从种植到烹饪、招聘/应聘、 音乐、魔术、 相亲等。新闻组可以面向全球,也可以只面向某个特定区域。
整个系统是一个由大量计算机组成的庞大的全球网络,计算机之间共享 Usenet 上的帖子。如果某个用户发了一个帖子到本地的 Usenet 计算机上, 这个帖子会被传播到其他相连的计算机上,再由这些计算机传到与它们相连的计算机上,直到这个帖子传播到了全世界,
每个人都收到这个帖子为止。 帖子在 Usenet 上的存活时间是有限的,这个时间可以由 Usenet系统管理员来指定,也可以为帖子指定一个过期的日期/时间。
每个系统都有一个已“订阅”的新闻组列表, 系统只接收感兴趣的新闻组里的帖子,而不是接收服务器上所有新闻组的帖子。 Usenet 新闻组的内容由提供者安排,很多服务都是公开的。但也有一些服务只允许特定用户使用,例如付费用户、 特定大学的学生等。 Usenet 系统管理员可能会进行一些设置来要求用户输入用户名和密码,管理员也可以设置是否只能上传或只能下载。
Usenet 正在逐渐退出人们的视线,主要