SocketServer模块
SocketServer 是标准库中一个高级别的模块。用于简化网络客户与服务器的实现。模块中,已经实现了一些可供使用的类
Socketserver模块简化了编写网络服务程序,同时socketserver模块也是python标准库中很多服务器框架的基础。
SocketServer模块的类
BaseServer: 包含服务器的核心功能与混合(mix-in)类的钩子功能。这个类用于派生,不要直接生成这个类的类对象,
可以考虑使用TCPServer 和 UDPServer。
TCPServer/UDPServer: 基本的网络同步 TCP/UDP 服务器
UnixStreamServer/UnixDatagramServer: 基本的基于文件同步 TCP/UDP 服务器
ForkingMixIn/ThreadingMixIn: 实现了核心的进程化或线程化的功能,用于与服务器类进行混合(mix-in),以提供一些异步特性。
不要直接生成这个类的对象
ForkingTCPServer/ForkingUDPServer: ForkingMixIn 和 TCPServer/UDPServer 的组合
ThreadingTCPServer/ThreadingUDPServer: ThreadingMixIn 和 TCPServer/UDPServer 的组合
BaseRequestHandler: 包含处理服务请求的核心功能。只用于派生新的类,不要直接生成这个类的对象,
可以考虑使用 StreamRequestHandler 或 DatagramRequestHandler
StreamRequestHandler/DatagramRequestHandler: TCP/UDP 服务器的请求处理类的一个实现
socketserver模块类介绍
SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端。即:每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个“线程”或者“进 程” 专门负责处理当前客户端的所有请求。
socketserver模块可以简化网络服务器的编写,python把网络服务抽象成两个主要的类,一个是server类,用于处理连接相关的网络操作,另一个是RequestHandler类,用于处理数据相关的操作。并且提供两个Mixln类,用于扩展server,实现多进程或者多线程。
Server类
它包含了五种server类,分别是 Baseserver(不直接对外服务);TCPServer(使用TCP协议) ;UDPServer(使用UDP协议),UinixStreamServer 和UnixDatagramServer(后面两个仅仅在unix环境下有用,一般不常用)
他们五个的关系如下:
RequestHandler类
所有requestHandler都继承BaseRequestHandler基类。
请求的基类是baserequesthandler,其中一般需要重写的方法就是handle方法,主要就是如何处理接下里的请求,在这个类中,主要有三个方法,分别是setup ,handle ,finish方法,在调用这个类的时候,先调用setup进行一些初始化的工作,然后调用handle方法进行处理请求,然后调用finish方法,做一些关闭连接什么的,在这个里面最主要的参数就是self.request,也就是请求的socket对象,其中可以发送消息sendall或者send,接受消息就是recv
在请求处理的子类中有两个,一个是SreamRequestHandle和DatagramRequestHandle,在这个里面重写了基类的setup方法和finish方法,handle方法没有重写,因为这个是留给用户做处理请求的方法
混合类(并发类)
两个混合类,一个是ForkingMixin,主要是用fork的,产生一个新的进程去处理;一个是ThreadingMixin,产生一个新的线程,主要是用来提供异步处理的能力,其余tcpserver和udpserver组合,又产生了新的四个类,从而提供异步处理的能力。
(在使用混合类和服务器类的时候,注意混合类需要写在前面,因为混合类重写了服务器类的方法,从而需要放在第一个位置。)
class socketserver.ForkingTCPServer
class socketserver.ForkingUDPServer
class socketserver.ThreadingTCPServer
class socketserver.ThreadingUDPServer
ThreadingTCPServer
ThreadingTCPServer实现的Soket服务器内部会为每个client创建一个 “线程”,该线程用来和客户端进行交互。
ThreadingTCPServer基础
1、使用ThreadingTCPServer:
1.1创建一个继承自 SocketServer.BaseRequestHandler 的类
1.2类中必须定义一个名称为 handle 的方法
1.3 启动ThreadingTCPServer
SocketServer实现服务器
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import SocketServer
class MyServer(SocketServer.BaseRequestHandler):
def handle(self):
# print self.request,self.client_address,self.server
conn = self.request
conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')
Flag = True
while Flag:
data = conn.recv(1024)
if data == 'exit':
Flag = False
elif data == '0':
conn.sendall('通过可能会被录音.balabala一大推')
else:
conn.sendall('请重新输入.')
if __name__ == '__main__':
server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyServer)
server.serve_forever()
客户端:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
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)
print 'receive:',data
inp = raw_input('please input:')
sk.sendall(inp)
if inp == 'exit':
break
sk.close()
ThreadingTCPServer源码剖析
ThreadingTCPServer的类图关系如下:
内部调用流程为:
1、启动服务端程序
2、执行 TCPServer.__init__ 方法,创建服务端Socket对象并绑定 IP 和 端口
3、执行 BaseServer.__init__ 方法,将自定义的继承自SocketServer.BaseRequestHandler 的类 MyRequestHandle赋值给 self.RequestHandlerClass
4、执行 BaseServer.server_forever 方法,While 循环一直监听是否有客户端请求到达 ...
5、当客户端连接到达服务器
6、执行 ThreadingMixIn.process_request 方法,创建一个 “线程” 用来处理请求
7、执行 ThreadingMixIn.process_request_thread 方法
8、执行 BaseServer.finish_request 方法,执行 self.RequestHandlerClass() 即:执行 自定义 MyRequestHandler 的构造方法(自动调用基类BaseRequestHandler的构造方法,在该构造方法中又会调用 MyRequestHandler的handle方法)
ThreadingTCPServer相关源码:
BaseServer
通过:在Pycharm执行
import SocketServer
SocketServer.BaseServer #在BaseServer点击CTRL+鼠标左键即可看到BaseServer的源码
TCPServer
import SocketServer
SocketServer.TCPServer #在TCPServer点击CTRL+鼠标左键即可看到TCPServer的源码
同理,ThreadingMixIn、 ThreadingTCPServer
RequestHandler相关源码
import SocketServer
SocketServer.BaseRequestHandler #在BaseRequestHandler点击CTRL+鼠标左键即可看到BaseRequestHandler的源码
实例:
服务器:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import SocketServer
class MyServer(SocketServer.BaseRequestHandler):
def handle(self):
# print self.request,self.client_address,self.server
conn = self.request
conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')
Flag = True
while Flag:
data = conn.recv(1024)
if data == 'exit':
Flag = False
elif data == '0':
conn.sendall('通过可能会被录音.balabala一大推')
else:
conn.sendall('请重新输入.')
if __name__ == '__main__':
server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyServer)
server.serve_forever()
客户端:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
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)
print 'receive:',data
inp = raw_input('please input:')
sk.sendall(inp)
if inp == 'exit':
break
sk.close()
源码精简:
import socket
import threading
import select
def process(request, client_address):
print request,client_address
conn = request
conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')
flag = True
while flag:
data = conn.recv(1024)
if data == 'exit':
flag = False
elif data == '0':
conn.sendall('通过可能会被录音.balabala一大推')
else:
conn.sendall('请重新输入.')
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个客户端链接(长连接)
ForkingTCPServer
ForkingTCPServer和ThreadingTCPServer的使用和执行流程基本一致,只不过在内部分别为请求者建立 “线程” 和 “进程”。
服务器
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import SocketServer
class MyServer(SocketServer.BaseRequestHandler):
def handle(self):
# print self.request,self.client_address,self.server
conn = self.request
conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')
Flag = True
while Flag:
data = conn.recv(1024)
if data == 'exit':
Flag = False
elif data == '0':
conn.sendall('通过可能会被录音.balabala一大推')
else:
conn.sendall('请重新输入.')
if __name__ == '__main__':
server = SocketServer.ForkingTCPServer(('127.0.0.1',8009),MyServer)
server.serve_forever()
客户端
#!/usr/bin/env python
# -*- coding:utf-8 -*-
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)
print 'receive:',data
inp = raw_input('please input:')
sk.sendall(inp)
if inp == 'exit':
break
sk.close()
以上ForkingTCPServer只是将 ThreadingTCPServer 实例中的代码:
server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyRequestHandler)
变更为:
server = SocketServer.ForkingTCPServer(('127.0.0.1',8009),MyRequestHandler)
SocketServer的ThreadingTCPServer之所以可以同时处理请求得益于 select 和 os.fork 两个东西,其实本质上就是在服务器端为每一个客户端创建一个进程,当前新创建的进程用来处理对应客户端的请求,所以,可以支持同时n个客户端链接(长连接)。
源码剖析参考 ThreadingTCPServer