Python 网络编程(SocketServer 模块)

SocketServer 模块

SocketServer 是标准库中的一个高级模块(Python 3.x 中重命名为socketserver),它的目

标是简化很多样板代码,它们是创建网络客户端和服务器所必需的代码。这个模块中有为你

创建的各种各样的类,如表2-3 所示。

通过复制前面展示的基本TCP 示例,我们将创建一个TCP 客户端和服务器。你会发现

它们之间存在明显的相似性,但是也应该看到我们如何处理一些繁琐的工作,于是你不必担

心样板代码。这些代表了你能够编写的最简单的同步服务器(为了将你的服务器配置为异步

运行,可以查看本章末尾的练习)。

除了为你隐藏了实现细节之外,另一个不同之处是,我们现在使用类来编写应用程序。

因为以面向对象的方式处理事务有助于组织数据,以及逻辑性地将功能放在正确的地方。

你还会注意到,应用程序现在是事件驱动的,这意味着只有在系统中的事件发生时,它们

才会工作。

事件包括消息的发送和接收。事实上,你会看到类定义只包括一个用来接收客户端消息

的事件处理程序。所有其他的功能都来自使用的SocketServer 类。此外,GUI 编程(见第5

章)也是事件驱动的。你会立即注意到它们的相似性,因为最后一行代码通常是一个服务器

的无限循环,它等待并响应客户端的服务请求。它工作起来几乎与本章前面的基础TCP 服务

器中的无限while 循环一样。

在原始服务器循环中,我们阻塞等待请求,当接收到请求时就对其提供服务,然后继续

等待。在此处的服务器循环中,并非在服务器中创建代码,而是定义一个处理程序,这样当

服务器接收到一个传入的请求时,服务器就可以调用你的函数。

创建SocketServer TCP 服务器

在示例2-8 中,首先导入服务器类,然后定义与之前相同的主机常量。其次是请求处理

程序类,最后启动它。更多细节请查看下面的代码片段。

python 复制代码
from SocketServer import(TCPServer as TCP,StreamRequestHandler as SRH)
from time import ctime

HOST=''
PORT=21567
ADDR=(HOST,PORT)

class MyRequestHandler(SRH):
    def handle(self):
        print('...Connected from:',self.client_address)
        self.wfile.write('[%s] %s' %(ctime(),self.rfile.readline()))

tcpServ=TCP(ADDR,MyRequestHandler)
print('Waiting for connection...')
tcpServ.serve_forever()

创建SocketServer TCP 客户端

如示例2-9 所示,这里的客户端很自然地非常像最初的客户端,比服务器像得多,但必

须稍微调整它以使其与新服务器很好地工作。

python 复制代码
from socket import *

HOST='localhost'
PORT=21567
BUFSIZE=1024
ADDR=(HOST,PORT)

while True:
    tcpCliSock=socket(AF_INET,SOCK_STREAM)
    tcpCliSock.connect(ADDR)
    data=raw_input('>')
    if not data:
        break
    tcpCliSock.send('%s\r\n'%data)
    data=tcpCliSock.recv(BUFSIZE)
    if not data:
        break
    print data.strip()
    tcpCliSock.close()

执行TCP 服务器和客户端

这里是SocketServer TCP 客户端的输出。

复制代码
$ tsTclntSS.py
> 'Tis but a scratch.
[Tue Apr 18 20:55:49 2006] 'Tis but a scratch.
> Just a flesh wound.
[Tue Apr 18 20:55:56 2006] Just a flesh wound.
>
$

这是服务器的输出。

复制代码
$ tsTservSS.py
waiting for connection...
...connected from: ('127.0.0.1', 53476)
.. .connected from: ('127.0.0.1', 53477)

此时的输出与最初的TCP 客户端和服务器的输出类似。然而,你应该会发现,我们连接

了服务器两次。