Python使用SocketServer模块编写基本服务器程序的教程


Posted in Python onJuly 12, 2016

SocketServer简化了网络服务器的编写。它有4个类:TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer。这4个类是同步进行处理的,另外通过ForkingMixIn和ThreadingMixIn类来支持异步。

创建服务器的步骤。首先,你必须创建一个请求处理类,它是BaseRequestHandler的子类并重载其handle()方法。其次,你必须实例化一个服务器类,传入服务器的地址和请求处理程序类。最后,调用handle_request()(一般是调用其他事件循环或者使用select())或serve_forever()。

集成ThreadingMixIn类时需要处理异常关闭。daemon_threads指示服务器是否要等待线程终止,要是线程互相独立,必须要设置为True,默认是False。

无论用什么网络协议,服务器类有相同的外部方法和属性。

在Python3中,本模块为socketserver模块。在Python 2中,本模块为SocketServer模块。所以在用import导入时,要分情况导入,否则会报错。导入的代码如下:

try:
  import socketserver   #Python 3
except ImportError:
  import SocketServer   #Python 2

SocketSerror模块包括许多可以简化TCP、UDP、UNIX域套接字  服务器实现的类。

一、处理程序
要使用本模块,必须定义一个继承于基类BaseRequestHandler的处理程序类。BaseRequestHandler类的实例h可以实现以下方法:
1、h.handle()  调用该方法执行实际的请求操作。调用该函数可以不带任何参数,但是几个实例变量包含有用的值。h.request包含请求,h.client_address包含客户端地址,h.server包含调用处理程序的实例。对于TCP之类的数据流服务,h.request属性是套接字对象。对于数据报服务,它是包含收到数据的字节字符串。
2、h.setup()   该方法在handle()之前调用。默认情况下,它不执行任何操作。如果希望服务器实现更多连接设置(如建立SSL连接),可以在这里实现。
3、h.finish()   调用本方法可以在执行完handle()之后执行清除操作。默认情况下,它不执行任何操作。如果setup()和handle()方法都不生成异常,则无需调用该方法。
如果知道应用程序只能操纵面向数据流的连接(如TCP),那么应从StreamRequestHandler继承,而不是BaseRequestHandler。StreamRequestHandler类设置了两个属性,h.wfile是将数据写入客户端的类文件对象,h.rfile是从客户端读取数据的类文件对象。
如果要编写针对数据包操作的处理程序并将响应持续返回发送方,那么它应当从DatagramRequestHandler继承。它提供的类接口与StramRequestHandler相同。

二、服务器
要使用处理程序,必须将其插入到服务器对象。定义了四个基本的服务器类。
(1)TCPServer(address,handler)   支持使用IPv4的TCP协议的服务器,address是一个(host,port)元组。Handler是BaseRequestHandler或StreamRequestHandler类的子类的实例。
(2)UDPServer(address,handler)   支持使用IPv4的UDP协议的服务器,address和handler与TCPServer中类似。
(3)UnixStreamServer(address,handler)   使用UNIX域套接字实现面向数据流协议的服务器,继承自TCPServer。
(4)UnixDatagramServer(address,handler)  使用UNIX域套接字实现数据报协议的服务器,继承自UDPServer。
所有四个服务器类的实例都有以下方法和变量:
1、s.socket   用于传入请求的套接字对象。
2、s.sever_address  监听服务器的地址。如元组("127.0.0.1",80)
3、s.RequestHandlerClass   传递给服务器构造函数并由用户提供的请求处理程序类。
4、s.serve_forever()  处理无限的请求
5、s.shutdown()   停止serve_forever()循环
6、s.fileno()   返回服务器套接字的整数文件描述符。该方法可以有效地通过轮询操作(如select()函数)使用服务器实例。

三、定义自定义服务器
服务器往往需要特殊的配置来处理不同的网络地址族、超时期、并发和其他功能,可以通过继承上面四个基本服务器类来自行定义。
可以通过混合类获得更多服务器功能,这也是通过进程或线程分支添加并发行的方法。为了实现并发性,定义了以下类:
(1)ForkingMixIn         将UNIX进程分支添加到服务器的混合方法,使用该方法可以让服务器服务多个客户。
(2)ThreadingMixIn    修改服务器的混合类,可以使用线程服务多个客户端。
要向服务器添加这些功能,可以使用多重继承,其中首先列出混了类。
由于并发服务器很常用,为了定义它,SocketServer预定义了以下服务器类:
(1)ForkingUDPServer(address,handler)  
(2)ForkingTCPServer(address,handler)
(3)ThreadingUDPServer(address,handler)
(4)ThreadingTCPServer(address,handler)
上面有点乱,现总结以下:
SocketServer模块中的类主要有以下几个:
1、BaseServer    包含服务器的核心功能与混合类(mix-in)的钩子功能。这个类主要用于派生,不要直接生成这个类的类对象,可以考虑使用TCPServer和UDPServer类。
2、TCPServer    基本的网络同步TCP服务器
3、UDPServer    基本的网络同步UDP服务器
4、ForkingMixIn   实现了核心的进程化功能,用于与服务器类进行混合(mix-in),以提供一些异步特性。不要直接生成这个类的对象。
5、ThreadingMixIn   实现了核心的线程化功能,用于与服务器类进行混合(mix-in),以提供一些异步特性。不要直接生成这个类的对象。
6、ForkingTCPServer     ForkingMixIn与TCPServer的组合
7、ForkingUDPServer    ForkingMixIn与UDPServer的组合
8、BaseRequestHandler
9、StreamRequestHandler    TCP请求处理类的一个实现
10、DataStreamRequestHandler   UDP请求处理类的一个实现
现在繁杂的事务都已经封装到类中了,直接使用类即可。

四、实例
1.使用SocketServer模块编写的TCP服务器端代码:

#! /usr/bin/env python
#coding=utf-8
"""使用SocketServer来实现简单的TCP服务器"""
from SocketServer import (TCPServer,StreamRequestHandler as SRH)
from time import ctime
class MyRequestHandler(SRH):
  def handle(self):
    print "connected from ",self.client_address
    self.wfile.write("[%s] %s" %(ctime(),self.rfile.readline()))
tcpSer=TCPServer(("",10001),MyRequestHandler)
print "waiting for connection"
tcpSer.serve_forever()
相应的TCP客户端代码:
#! /usr/bin/env python
#coding=utf-8
from socket import *
BUFSIZE=1024
#每次都要创建新的连接
while True:
  tcpClient=socket(AF_INET,SOCK_STREAM)
  tcpClient.connect(("localhost",10001))
  data=raw_input(">")
  if not data:
    break
  tcpClient.send("%s\r\n" %data)
  data1=tcpClient.recv(BUFSIZE)
  if not data1:
    break
  print data1.strip()
  tcpClient.close()

2.异步服务器的实现

ThreadingMixIn的例子:

import socketimport threadingimport SocketServerclass ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):

  def handle(self):
    data = self.request.recv(1024)
    cur_thread = threading.current_thread()
    response = "{}: {}".format(cur_thread.name, data)
    self.request.sendall(response)class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
  passdef client(ip, port, message):
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  sock.connect((ip, port))
  try:
    sock.sendall(message)
    response = sock.recv(1024)
    print "Received: {}".format(response)
  finally:
    sock.close()if __name__ == "__main__":
  # Port 0 means to select an arbitrary unused port
  HOST, PORT = "localhost", 0

  server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
  ip, port = server.server_address  # Start a thread with the server -- that thread will then start one
  # more thread for each request
  server_thread = threading.Thread(target=server.serve_forever)
  # Exit the server thread when the main thread terminates
  server_thread.daemon = True
  server_thread.start()
  print "Server loop running in thread:", server_thread.name

  client(ip, port, "Hello World 1")
  client(ip, port, "Hello World 2")
  client(ip, port, "Hello World 3")

  server.shutdown()

执行结果:

$ python ThreadedTCPServer.py
Server loop running in thread: Thread-1
Received: Thread-2: Hello World 1
Received: Thread-3: Hello World 2
Received: Thread-4: Hello World 3
Python 相关文章推荐
Python 常用string函数详解
May 30 Python
浅谈Python实现Apriori算法介绍
Dec 20 Python
python 读取.csv文件数据到数组(矩阵)的实例讲解
Jun 14 Python
python3读取csv和xlsx文件的实例
Jun 22 Python
Python面向对象程序设计OOP入门教程【类,实例,继承,重载等】
Jan 05 Python
python 计算数据偏差和峰度的方法
Jun 29 Python
Flask框架学习笔记之路由和反向路由详解【图文与实例】
Aug 12 Python
python函数修饰符@的使用方法解析
Sep 02 Python
Pytoch之torchvision.transforms图像变换实例
Dec 30 Python
Django ModelForm操作及验证方式
Mar 30 Python
numpy的Fancy Indexing和array比较详解
Jun 11 Python
Python3如何使用range函数替代xrange函数
Oct 05 Python
使用Python的Flask框架表单插件Flask-WTF实现Web登录验证
Jul 12 #Python
Python的Flask框架标配模板引擎Jinja2的使用教程
Jul 12 #Python
深度定制Python的Flask框架开发环境的一些技巧总结
Jul 12 #Python
Python的面向对象编程方式学习笔记
Jul 12 #Python
Python使用cookielib模块操作cookie的实例教程
Jul 12 #Python
Python网络编程中urllib2模块的用法总结
Jul 12 #Python
Python中内置的日志模块logging用法详解
Jul 12 #Python
You might like
这部番真是良心,画质好到像风景区,剧情让人跟着小公会热血沸腾
2020/03/10 日漫
php 连接mssql数据库 初学php笔记
2010/03/01 PHP
php后退一页表单内容保存实现方法
2012/06/17 PHP
PHP 获取ip地址代码汇总
2015/07/05 PHP
详解WordPress中过滤链接与过滤SQL语句的方法
2015/12/18 PHP
PHP实现限制IP访问的方法
2017/04/20 PHP
又一个小巧的图片预加载类
2007/05/05 Javascript
兼容IE与firefox火狐的回车事件(js与jquery)
2010/10/20 Javascript
js制作简易年历完整实例
2015/01/28 Javascript
jQuery实现鼠标单击网页文字后在文本框显示的方法
2015/05/06 Javascript
JS模仿腾讯图片站的图片翻页按钮效果完整实例
2016/06/21 Javascript
JavaScript实现简易的天数计算器实例【附demo源码下载】
2017/01/18 Javascript
js仿QQ邮箱收件人选择与搜索功能
2017/02/10 Javascript
BootStrap表单时间选择器详解
2017/05/09 Javascript
详解webpack介绍&安装&常用命令
2017/06/29 Javascript
JS通过识别id、value值对checkbox设置选中状态
2020/02/19 Javascript
简单了解Vue + ElementUI后台管理模板
2020/04/07 Javascript
js 解析 JSON 数据简单示例
2020/04/21 Javascript
[42:25]EG vs Spirit Supermajor 败者组 BO3 第二场 6.4
2018/06/05 DOTA
[01:34:42]NAVI vs EG 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
用Python写一个模拟qq聊天小程序的代码实例
2019/03/06 Python
pyqt 实现在Widgets中显示图片和文字的方法
2019/06/13 Python
基于python实现对文件进行切分行
2020/04/26 Python
python中使用input()函数获取用户输入值方式
2020/05/03 Python
Python 如何创建一个简单的REST接口
2020/07/30 Python
pycharm 2020.2.4 pip install Flask 报错 Error:Non-zero exit code的问题
2020/12/04 Python
英国厨房与餐具用品为主的设计品牌:Joseph Joseph
2018/04/26 全球购物
ManoMano英国:欧洲第一家专注于DIY和园艺市场的电商平台
2020/03/12 全球购物
Linux常见面试题
2013/03/18 面试题
工作迟到检讨书
2014/02/21 职场文书
歌唱比赛策划方案
2014/06/06 职场文书
停电调休通知
2015/04/16 职场文书
2015年保管员工作总结
2015/04/30 职场文书
董事长新年致辞
2015/07/29 职场文书
代码解析React中setState同步和异步问题
2021/06/03 Javascript
tomcat正常启动但网页却无法访问的几种解决方法
2022/05/06 Servers