Python网络编程篇之socketserver
1.socketserver模块和类
socketserver是标准库中的一个高级模块,目标是简化很多样板代码(创建网络客户端和服务器所必须的代码)
这个模块封装了socket编程所需要的各种各样的类,现在可以使用类来编写应用程序。
因为以面向对象的方式处理事务有助于组织数据,以及逻辑性地将功能放在正确的地方,应用程序现在是时间驱动的,这意味着只有在系统中的时间发生时,它才会工作。
SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端。即:每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个“线程”或者“进程” 专门负责处理当前客户端的所有请求。
socketserver模块可以简化网络服务器的编写,Python把网络服务抽象成两个主要的类
一个是Server类,用于处理连接相关的网络操作
另外一个则是RequestHandler类,用于处理数据相关的操作。并且提供两个MixIn 类,用于扩展 Server,实现多进程或多线程。
类的描述
1.BaseServer 包含核心服务器功能和 mix-in类的钩子;仅用于推导,这样不会创建这个类的实例;可以用TCPServer 或 UDPServer 创建类的实例
2.TCPServer/UDPServer 基础的网络同步TCP/UDP服务器
3.UnixStreamServer/UnixDatagramServer 基于文件的基础同步TCp/UDP服务器
4.ForkingMixIn/ThreadingMixIn 核心派出或线程功能;只用做mix-in类与一个服务器类配合实现一些异步性;不能直接实例化这个类
5.ThreadingTCPServer/ThreadingUDPServer ThreadingMixIn 和 TCPServer/UDPServer的组合
6.ForkingTCPServer/ForkingUDPServer ForkingMixIn 和 TCPServer/UDPServer的组合
7.BaseRequestHandler 包含处理服务器请求的核心功能;仅仅用于推导,这样无法创建这个类的实例;可以用StreamRequestHandler 或 DatagramRequestHandler 创建类的实例
8.StreamRequestHandler/DatagramRequestHandler 实现Tcp/UDP服务器的服务处理器
四个基础类的继承关系
+------------+
| BaseServer |
+------------+
|
v
+-----------+ +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+ +------------------+
|
v
+-----------+ +--------------------+
| UDPServer |------->| UnixDatagramServer |
+-----------+ +--------------------+
这四个类使用"同步"来处理请求。只有处理完所有请求后,才可以开始处理新的请求!不适合使用在处理单个请求需要花费大量时间的场合。因为需要花费大量的计算时间,或者这因为它会返回大量的数据导致客户端处理速度变得很慢。解决方法是创建单独的进程或者线程处理每一个请求。在类内部的ForkingMixIn和ThreadingMixIn 组合可以支持"异步"的操作。
所以,让你的socketserver并发起来, 必须选择使用以下一个多并发的类
class socketserver.
ForkingTCPServer
class socketserver.
ForkingUDPServer
class socketserver.
ThreadingTCPServer
class socketserver.
ThreadingUDPServer
2.ThreadingTCPServer
ThreadingTCPServer实现的Soket服务器内部会为每个client创建一个 “线程”,该线程用来和客户端进行交互。
首先,必须通过继承BaseRequestHandler类并重写handle()方法来创建请求处理程序类; 这个方法将处理传入的请求。
其次,必须实例化其中一个服务器类,并将其传递给服务器的地址和请求处理程序类。
然后,调用服务器对象的handle_request()or serve_forever()方法来处理一个或多个请求。
最后,调用server_close()关闭套接字。
ThreadingTCPServer---->TCPServer ------>BaseServer------>RequestHandlerClass
| (__init__) server_forever
| finish_request
|-----> ThreadingMixIn.process_request()
|----->ThreadingMixIn.process_request_thread()
内部调用流程为:
- 启动服务端程序
- 执行 TCPServer.__init__ 方法,创建服务端Socket对象并绑定 IP 和 端口
- 执行 BaseServer.__init__ 方法,将自定义的继承自SocketServer.BaseRequestHandler 的类 MyRequestHandle赋值给self.RequestHandlerClass
- 执行 BaseServer.server_forever 方法,While 循环一直监听是否有客户端请求到达 ...
- 当客户端连接到达服务器
- 执行 ThreadingMixIn.process_request 方法,创建一个 “线程” 用来处理请求
- 执行 ThreadingMixIn.process_request_thread 方法
- 执行 BaseServer.finish_request 方法,执行 self.RequestHandlerClass() 即:执行 自定义 MyRequestHandler 的构造方法(自动调用基类BaseRequestHandler的构造方法,在该构造方法中又会调用 MyRequestHandler的handle方法)
服务端
# -*- coding: utf-8 -*-
# 2017/11/25 20:15
import socketserver class MyServer(socketserver .BaseRequestHandler):
def handle(self):
# print self.request,self.client_address,self.server
conn = self.request
conn.sendall(bytes('欢迎致电 10086,0转人工服务.',encoding='utf8'))
Flag = True
while Flag:
data = conn.recv(1024)
data = str(data, encoding='utf8')
if data == 'exit':
Flag = False
elif data == '':
conn.sendall(bytes('通过可能会被录音',encoding='utf8'))
else:
conn.sendall(bytes('请重新输入.',encoding='utf8')) if __name__ == '__main__':
server = socketserver .ThreadingTCPServer(('127.0.0.1',8009),MyServer)
server.serve_forever()
服务端源码模拟
# -*- coding: utf-8 -*-
# 2017/11/25 20:37
import socket
import threading
import select def process(request, client_address):
print(request,client_address)
conn = request
conn.sendall(bytes('欢迎致电 10086,请输入1xxx,0转人工服务.', encoding='utf8'))
Flag = True
while Flag:
data = conn.recv(1024)
data = str(data, encoding='utf8')
if data == 'exit':
Flag = False
elif data == '':
print(data)
conn.sendall(bytes('通过可能会被录音.balabala一大推', encoding='utf8'))
else:
conn.sendall(bytes('请重新输入.', encoding='utf8')) sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sk.bind(('127.0.0.1',8002))
sk.listen(5) while True:
r, w, e = select.select([sk,],[],[],1)
print('looping')
if sk in r:
print('get request')
request, client_address = sk.accept()
t = threading.Thread(target=process, args=(request, client_address))
t.daemon = False
t.start()
sk.close()
如精简代码可以看出,SocketServer的ThreadingTCPServer之所以可以同时处理请求得益于 select 和 Threading 两个东西,其实本质上就是在服务器端为每一个客户端创建一个线程,当前线程用来处理对应客户端的请求,所以,可以支持同时n个客户端链接(长连接)。
客户端
# -*- coding: utf-8 -*-
# 2017/11/25 20:16
import socket
ip_port = ('127.0.0.1',8009)
sk = socket.socket()
sk.connect(ip_port)
sk.settimeout(5) while True:
data = sk.recv(1024)
data = str(data, encoding='utf8')
print('receive:',data)
inp = input('please input:')
sk.sendall(bytes(inp,encoding="utf8"))
if inp == 'exit':
break sk.close()
ForkingTCPServer只是将 ThreadingTCPServer 实例中的代码:
SocketServer的ThreadingTCPServer之所以可以同时处理请求得益于 select 和 os.fork 两个东西,其实本质上就是在服务器端为每一个客户端创建一个进程,当前新创建的进程用来处理对应客户端的请求,所以,可以支持同时n个客户端链接(长连接)。
server
=
SocketServer.ThreadingTCPServer((
'127.0.0.1'
,
8009
),MyRequestHandler)
变更为:
server
=
SocketServer.ForkingTCPServer((
'127.0.0.1'
,
8009
),MyRequestHandler)
3.class socketserver.
BaseServer
(server_address, RequestHandlerClass) 主要有以下方法
类socketserver.BaseServer(server_address,RequestHandlerClass)
这是模块中所有服务器对象的超类。它定义了下面给出的接口,但不实现大多数在子类中完成的方法。这两个参数存储在相应的server_address和RequestHandlerClass属性中。
fileno()
返回服务器正在侦听的套接字的整数文件描述符。这个函数通常被传递给选择器,允许在同一个进程中监视多个服务器。
handle_request()
处理一个请求。该函数按顺序调用以下方法:get_request(),verify_request()和process_request()。如果处理程序类的用户提供的handle()方法引发异常,则将调用服务器的handle_error()方法。如果在超时秒内没有收到请求,则会调用handle_timeout(),并返回handle_request()。
serve_forever(POLL_INTERVAL = 0.5)
处理请求直到显式关闭()请求。轮询关闭每个poll_interval秒。忽略超时属性。它还调用service_actions(),子类或mixin可以使用它来提供特定于给定服务的操作。例如,ForkingMixIn类使用service_actions()来清理僵尸子进程。
在版本3.3中进行了更改:将service_actions调用添加到了serve_forever方法。
service_actions()
这在serve_forever()循环中被调用。这个方法可以被子类或mixin类覆盖,以执行特定于给定服务的操作,例如清理操作。
3.3版本中的新功能
shutdown()
告诉serve_forever()循环停止并等待,直到它结束。
server_close()
清理服务器。可能会被覆盖。
address_family
服务器套接字所属的协议族。通常的例子是socket.AF_INET和socket.AF_UNIX。
RequestHandlerClass
用户提供的请求处理程序类;这个类的一个实例是为每个请求创建的。
server_address
服务器正在侦听的地址。地址格式因协议族而异,有关详细信息,请参阅套接字模块的文档。对于Internet协议,这是一个包含给出地址的字符串的元组,以及一个整数端口号:('127.0.0.1',80)。
socket
服务器将侦听传入请求的套接字对象。
服务器类支持以下类变量:
allow_reuse_address
服务器是否允许重用地址。这默认为False,可以在子类中设置来更改策略。
request_queue_size
请求队列的大小。如果处理单个请求需要很长时间,则在服务器繁忙时到达的所有请求都会被放入一个队列中,最多为request_queue_size请求。一旦队列已满,来自客户端的进一步请求将会得到“连接被拒绝”错误。默认值通常是5,但这可以由子类覆盖。
socket_type
服务器使用的套接字的类型; socket.SOCK_STREAM和socket.SOCK_DGRAM是两个常见的值。
timeout
超时持续时间(以秒为单位);如果不需要超时,则超时。如果handle_request()在超时期限内没有收到传入的请求,则调用handle_timeout()方法。
有许多服务器方法可以被TCPServer等基本服务器类的子类覆盖;这些方法对服务器对象的外部用户没有用处。
finish_request()
实际上通过实例化RequestHandlerClass并调用其handle()方法来处理请求。
get_request()
必须接受来自套接字的请求,并返回包含要用于与客户端通信的新套接字对象的2元组以及客户端的地址。
handle_error(request,client_address)
如果RequestHandlerClass实例的handle()方法引发异常,则调用此函数。默认操作是将回溯打印到标准输出,并继续处理更多的请求。
handle_timeout()
当timeout属性被设置为None以外的值时,该函数被调用,超时时间已经过去,没有收到请求。派生服务器的默认动作是收集退出的任何子进程的状态,而在线程服务器中,这个方法什么也不做。
process_request(request,client_address)
调用finish_request()来创建RequestHandlerClass的一个实例。如果需要,这个函数可以创建一个新的进程或线程来处理请求; ForkingMixIn和ThreadingMixIn类都是这样做的。
server_activate()
由服务器的构造函数调用以激活服务器。 TCP服务器的默认行为只是在服务器套接字上调用listen()。可能会被覆盖。
server_bind()
由服务器的构造函数调用,将套接字绑定到所需的地址。可能会被覆盖。
verify_request(request,client_address)
必须返回一个布尔值;如果值为True,
Python网络编程篇之socketserver的更多相关文章
- Python网络编程篇之socket
1 socket 插座?呵呵,想多了,翻译过来意思是套接字! A network socket is an internal endpoint for sending or receiving dat ...
- Python网络编程03----Python3.*中socketserver
socketserver(在Python2.*中的是SocketServer模块)是标准库中一个高级别的模块.用于简化网络客户与服务器的实现(在前面使用socket的过程中,我们先设置了socket的 ...
- Python网络编程篇之select和epoll
1. select 原理 在多路复⽤的模型中, ⽐较常⽤的有select模型和epoll模型. 这两个都是系统接⼝, 由操作系统提供. 当然, Python的select模块进⾏了更⾼级的封装. ⽹络 ...
- python 网络编程篇
基础模拟通话网络程序: #客户端 import socket client = socket.socket() client.connect(('localhost',6969)) client.se ...
- python学习之路网络编程篇(第四篇)
python学习之路网络编程篇(第四篇) 内容待补充
- Python网络编程03 /缓存区、基于TCP的socket循环通信、执行远程命令、socketserver通信
Python网络编程03 /缓存区.基于TCP的socket循环通信.执行远程命令.socketserver通信 目录 Python网络编程03 /缓存区.基于TCP的socket循环通信.执行远程命 ...
- Python 网络编程(二)
Python 网络编程 上一篇博客介绍了socket的基本概念以及实现了简单的TCP和UDP的客户端.服务器程序,本篇博客主要对socket编程进行更深入的讲解 一.简化版ssh实现 这是一个极其简单 ...
- day7_直播_网络编程篇(元昊老师著)
网络编程篇计算机网络: 多台独立的计算机用网络通信设备连接起来的网络.实现资源共享和数据传递. 比如,我们之前的学过的知识可以将D盘的一个文件传到C盘,但如果你想从你的电脑传一个文件到我的电脑上目前是 ...
- 图解Python网络编程
返回目录 本篇索引 (1)基本原理 (2)socket模块 (3)select模块 (4)asyncore模块 (5)asynchat模块 (6)socketserver模块 (1)基本原理 本篇指的 ...
随机推荐
- VB6文件操作自定义函数合集之一
'--与文件及文件夹操作相关的函数 '--必须引用FSO的ACTIVE OBJECT Dim strList As String '--列表串,返回文件列表 '================ '-- ...
- win10 输入法禁用IME
发现了win10 没法输入,因为禁用IME 右击开始 计算机管理 任务计划程序 打开到Microsoft/Windows/TextServicesFramework 选择操作运行 选择如果任务失 ...
- 快速排序算法分析--C++版
快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用,再加上快速排序思想----分治法也确实实用,因此很多软件公司的笔试面试喜欢考这个. 快速排序是C.R.A.Hoar ...
- javascript入门知识点总结(一)
学了几天javascript,现总结一下原生javascript的基本知识点. 一.javascript基本知识 变量 定义: var a = 123; var b = 'abc'; //连写 var ...
- web.xml中<init-param>报错
报错信息如下图: 控制台报错:严重: Servlet /*** threw load() exceptionjava.lang.ClassNotFoundException: MyApplicatio ...
- Google Guava
公司用到了 Joiner HashMultimap 等 都是属于Google Guava包中的东西 官方文档 http://ifeve.com/google-guava/ 有时间了整理一下
- Vue源码后记-其余内置指令(2)
-- 指令这个讲起来还有点复杂,先把html弄上来: <body> <div id='app'> <div v-if="vIfIter" v-bind ...
- getSystemService详解
android的后台运行在很多service,它们在系统启动时被SystemServer开启,支持系统的正常工作,比如MountService监听是否有SD卡安装及移除,ClipboardServi ...
- ASP.NET Core 认证与授权[4]:JwtBearer认证
在现代Web应用程序中,通常会使用Web, WebApp, NativeApp等多种呈现方式,而后端也由以前的Razor渲染HTML,转变为Stateless的RESTFulAPI,因此,我们需要一种 ...
- Django web框架篇:基础
对于web开发者来说,socket是基础.因为Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. 对于真实开发中的python web程序来说,一般会分为两 ...