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 用户登录验证的小例子
Mar 06 Python
详细解析Python当中的数据类型和变量
Apr 25 Python
python通过openpyxl生成Excel文件的方法
May 12 Python
python pandas dataframe 行列选择,切片操作方法
Apr 10 Python
python远程连接服务器MySQL数据库
Jul 02 Python
python3用PIL把图片转换为RGB图片的实例
Jul 04 Python
python生成随机红包的实例写法
Sep 02 Python
Django 自定义分页器的实现代码
Nov 24 Python
Jupyter Notebook折叠输出的内容实例
Apr 22 Python
Django框架配置mysql数据库实现过程
Apr 22 Python
python 在threading中如何处理主进程和子线程的关系
Apr 25 Python
python数据可视化使用pyfinance分析证券收益示例详解
Nov 20 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
用PHP实现的生成静态HTML速度快类库
2007/03/31 PHP
php通过Chianz.com获取IP地址与地区的方法
2015/01/14 PHP
Laravel框架实现的rbac权限管理操作示例
2019/01/16 PHP
ThinkPHP5.0框架验证码功能实现方法【基于第三方扩展包】
2019/03/11 PHP
通过代码实例解析PHP session工作原理
2020/12/11 PHP
List the Codec Files on a Computer
2007/06/18 Javascript
javascript cookie解码函数(兼容ff)
2008/03/17 Javascript
extjs 学习笔记 四 带分页的grid
2009/10/20 Javascript
Javascript在IE下设置innerHTML时出现未知的运行时错误的解决方法
2011/01/12 Javascript
深入领悟JavaScript中的面向对象
2013/11/18 Javascript
js中top的作用深入剖析
2014/03/04 Javascript
jQuery中dom元素上绑定的事件详解
2015/04/24 Javascript
HTML+CSS+JS实现完美兼容各大浏览器的TABLE固定列
2015/04/26 Javascript
jQuery实现鼠标滑过点击事件音效试听
2015/08/31 Javascript
jQuery 出现Cannot read property ‘msie’ of undefined错误的解决方法
2016/11/23 Javascript
实现单层json按照key字母顺序排序的示例
2017/12/06 Javascript
Vue-router 切换组件页面时进入进出动画方法
2018/09/01 Javascript
如何实现小程序与小程序之间的跳转
2020/11/04 Javascript
[46:43]DOTA2上海特级锦标赛主赛事日 - 1 胜者组第一轮#2LGD VS MVP.Phx第二局
2016/03/02 DOTA
Python制作简单的网页爬虫
2015/11/22 Python
python中的set实现不重复的排序原理
2018/01/24 Python
导入tensorflow时报错:cannot import name 'abs'的解决
2019/10/10 Python
Python 日志logging模块用法简单示例
2019/10/18 Python
python PIL/cv2/base64相互转换实例
2020/01/09 Python
HTML5各种头部meta标签的功能(推荐)
2017/03/13 HTML / CSS
N:Philanthropy官网:美国洛杉矶基础款服装
2020/06/09 全球购物
澳大利亚在线批发商:Simply Wholesale
2021/02/24 全球购物
《愚公移山》教学反思
2014/02/20 职场文书
大型会议接待方案
2014/03/01 职场文书
护士演讲稿优秀范文
2014/04/30 职场文书
基层党支部公开承诺书
2014/05/29 职场文书
验房委托书
2014/08/30 职场文书
借名购房协议书范本
2014/10/06 职场文书
2014年人民调解工作总结
2014/12/08 职场文书
2015年世界卫生日活动总结
2015/02/09 职场文书
退休职工欢送会致辞
2015/08/01 职场文书