本节书摘来自异步社区《Python核心编程(第3版)》一书中的第2章,第2.8节,作者[美] Wesley Chun(卫斯理 春),孙波翔 李斌 李晗 译,更多章节内容可以访问云栖社区“异步社区”公众号查看。
2.8 练习
2-1 套接字。面向连接的套接字和无连接套接字之间的区别是什么?
2-2 客户端/服务器架构。用自己的话描述这个术语的意思,并给出几个例子。
2-3 套接字。TCP和UDP之中,哪种类型的服务器接受连接,并将它们转换到独立的套接字进行客户端通信?
2-4 客户端。更新TCP(tsTclnt.py)和UDP(tsUclnt.py)客户端,以使得服务器名称无须硬编码到应用程序中。此外,应该允许用户指定主机名和端口号,且如果二者中任何一个或者全部参数丢失,那么应该使用默认值。
2-5 网络互连和套接字。实现Python库参考文档中关于socket模块中的TCP客户端/服务器程序示例,并使其能够正常工作。首先运行服务器,然后启动客户端。也可以在http://docs.python.org/library/socket#example 网址中找到在线源码。
如果你觉得示例中服务器的功能太单调,那么可以更新服务器代码,以使它具有更多功能,令其能够识别以下命令。
date 服务器将返回其当前日期/时间戳,即time.ctime()。
os 获取操作系统信息(os.name)。
ls 列出当前目录文件清单(提示:os.listdir()列出一个目录,os.curdir是当前目录)。选做题:接受ls dir命令,返回dir目录中的文件清单。
你不需要一个网络来完成这个任务,因为你的计算机可以与自己通信。请注意,在服务器退出之后,在再次运行它之前必须清除它的绑定。否则,可能会遇到“端口已绑定”的错误提示。此外,操作系统通常会在5分钟内清除绑定,所以请耐心等待。
2-6 Daytime服务。使用socket.getservbyname()来确定使用UDP协议的“daytime”服务的端口号。检查getservbyname()的文档以获得其准确的使用语法(即socket. getservbyname. _ doc_)。那么,现在编写一个应用程序,使该应用程序能够通过网络发送一条虚拟消息,然后等待服务器回复。一旦你收到服务器的回复,就将其显示到屏幕上。
2-7 半双工聊天。创建一个简单的半双工聊天程序。指定半双工,我们的意思就是,当建立一个连接且服务开始后,只有一个人能打字,而另一个参与者在得到输入消息提示之前必须等待消息。并且,一旦发送者发送了一条消息,在他能够再次发送消息之前,必须等待对方回复。其中,一位参与者将在服务器一侧,而另一位在客户端一侧。
2-8 全双工聊天。更新上一个练习的解决方案,修改它以使你的聊天服务现在成为全双工模式,意味着通信两端都可以发送并接收消息,并且二者相互独立。
2-9 多用户全双工聊天。进一步修改你的解决方案,以使你的聊天服务支持多用户。
2-10 多用户、多房间、全双工聊天。现在让你的聊天服务支持多用户和多房间功能。
2-11 Web客户端。编写一个TCP客户端,使其连接到你最喜欢的网站(删除“http://” 和任何后续信息;只使用主机名)的80端口。一旦建立一个连接,就发送HTTP命令字符串GET / n,并将服务器返回的所有数据写入一个文件中(GET命令会检索一个Web页面,/file表明要获取的文件,n将命令发送到服务器)。检查检索到的文件的内容。内容是什么?你如何检查能确保所接收到的数据是正确的?(注意:你可能必须在命令字符串后面插入一个或两个换行符,通常一个就能正常工作)
2-12 睡眠服务器。创建一个睡眠服务器。客户端将请求一段时间之后进入睡眠状态。服务器将代表客户端发送命令,然后向客户端返回一条表明成功的消息。客户端应该睡眠或空闲所请求的时间长度。这是一个远程过程调用的简单实现,此过程中一个客户端的请求会通过网络调用另一台计算机上的命令。
2-13 名称服务器。设计并实现一个名称服务器。该服务器负责维护一个包含主机名-端口号对的数据库,也许还有对应服务器所提供的服务的字符串描述。针对一个或多个现有的服务器,注册它们的服务到你的名称服务器中(注意,在这种情况下,这些服务器是名称服务器的客户端)。
每个启动的客户端都不知道它们所寻找的服务器地址。同样地,对于名称服务器的客户端来说,这些客户端应该发送一个请求到名称服务器,以指示它们正在寻找什么类型的服务。作为回复,名称服务器会向该客户端返回一个主机名-端口号对,然后该客户端就可以连接到适当的服务器来处理它的请求。
选做题:
1)为名称服务器添加缓存流行请求的功能。
2)为你的名称服务器添加日志记录功能,跟踪哪些服务器注册了名称服务器,以及客户端正在请求哪些服务。
3)你的名称服务器应该定期通过相应的端口号ping已经注册的主机,以确保它们的服务确实处于开启状态。反复的失败将会导致名称服务器将其从服务列表中划去。
你可以为那些注册了名称服务器的服务器实现真正的服务,或者仅仅使用虚拟服务器(仅仅应答一个请求)。
2-14 错误检查和优雅的关闭。本章所有的客户端/服务器示例代码都缺乏错误检查功能。我们并没有处理以下几种场景,例如,用户按Ctrl+C快捷键退出服务器或Ctrl+D快捷键终止客户端输入,也没有检查其他对raw_input()的不适当输入或处理网络错误。因为这个缺陷,经常我们终止一个应用程序时并没有关闭套接字,很可能会导致丢失数据。本练习中,在示例中选择一对客户端/服务器程序,并添加足够的错误检查,这样每个应用程序就能正确地关闭,即关闭网络连接。
2-15 异步性和SocketServer/socketserver。使用TCP服务器的示例,并使用其中一个mix-in类来支持一个异步服务器。为了测试你的服务器,同时创建并运行多个客户端,并交叉显示你的服务器满足二者中请求的输出。
2-16 *扩展SocketServer类。在SocketServer TCP服务器代码中,我们不得不从原始的基础TCP客户端中修改客户端,因为SocketServer类没有维护多个请求之间的连接。
a)继承TCPServer和StreamRequestHandler类并重新设计服务器,使其能够为每个客户端维持并使用单个连接(而不是每个请求一个连接)。
b)将前面练习的解决方案集成到(a)部分中的方案中,这样就可以并行为多个客户端提供服务。
2-17 *异步系统。研究至少5个基于Python的不同异步系统,可以从Twisted、Greenlets、Tornado、Diesel、Concurrence、Eventlet、Gevent等中选择。描述它们是什么,对它们进行分类,并找到它们之间的相似点和差异性,然后创建一些演示代码示例。