简介
socketserver 用于实现服务器可以多并发接收请求时。socketserver的相关功能已经被打包成一个模块。使用时需要导入这个模块即可使用其中的方法。
import socketserver
class MyServer(socketserver.BaseRequestHandler): #是一个基础服务类,用于监控,绑定IP地址等操作
def handle(self):#客户端请求处理的方法,所有的请求交互都在handle里执行
print("服务端启动......")
while True:
conn = self.request # 在源码中可以查看到,request就是创建对象时传入进去的服务端的IP地址与端口。每一个请求都会实例化MyTCPHandler(socketserver.BaseRequestHandler):
print(self.client_address)
while True:
client_data = conn.recv(1024)
print(str(client_data,"utf8"))
print("waiting......")
server_response = input(">>>:")
conn.sendall(bytes(server_response,"utf8"))
#conn.sendall(client_data)
conn.close()
if __name__ == "__main__":
server = socketserver.ThreadingTCPServer(("127.0.0.1",9200),MyServer)
server.serve_forever()
import socket
ip_port = ("127.0.0.1",9200)
sk = socket.socket()
sk.connect(ip_port)
print("客户端已启动:")
while True:
inp = input(">>>:")
sk.sendall(bytes(inp,"utf8"))
if inp == "exit":
break
server_response = sk.recv(1024)
print(str(server_response,"utf8"))
sk.close()
socketserver 简介
python 将网络服务抽象成两个订的类,一个是Sever类,用于处理连接相关的网络操作,另外一个则是RequestHandler类,用于处理数据相关的操作。并且提供两个MixIn类,用于扩展Server,实现多进程或多线程。
Server类
在Python的socketserver中,共包含5种Server类:
- BaseServer:不直接对外服务
- TCPServer:提供TCP连接的服务
- UDPServer:提供UDP连接的服务
- UnixStreamServer:不常用,主要应用在AF_unix中使用
- UnixDatagramServer:不常用,主要应用在AF_unix中使用
################################################################
There are five classes in an inheritance diagram, four of which represent
synchronous servers of four types:
+----------------+
| BaseServer |
+----------------+
|
v
+---------------+********* +-------------------------+
| TCPServer |------->| UnixStreamServer |
+---------------+*********+-------------------------+
|
v
+---------------+*********+-----------------------------+
| UDPServer |------->| UnixDatagramServer |
+---------------+*********+-----------------------------+
###############################################################
class BaseServer:
"""Base class for server classes.
class TCPServer(BaseServer):
"""Base class for various socket-based server classes.
Defaults to synchronous IP stream (i.e., TCP)
class UDPServer(TCPServer):
"""UDP server class."""
RequestHandler类
所有的RequestHandler类都继承BaseRequestHandler类。
创建一个socketserver
至少包含以下步骤:
- 必需创建一个“request handler”的类 做为BaseRequestHandler的子类,并且重写它的"handler()"方法,这个方法用于处理客户端请求。
- 必需通过这个子类创建一个相应的对象,传递服务器的IP地址和这个“request handler”类。
- 使用handle_request() 或者 serve_forever()方法,这个个server的对象这处理一个或者多个请求
- 最后,使用server_close()关闭这个socket。
分析代码的执行过程
- 运行“server = socketserver.ThreadingTCPServer((“127.0.0.1”,9200),MyServer)”,所以找先到到ThreadingTCPServer()
- 步骤1中其实是一个通过类创建对象的过程,所以在创建对象的时候会自动执行相应类中的“__init__()”方法.
- 通过查看源码,找到了“class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass”类,但是没有定义任何方法,所以往父类查找。
- 根据父类查找顺序,先找左边的父类“ThreadingMixIn”。发现其下面并没有“__init__()”方法.,所以找“TCPServer”这个父类,可查看到“__init__()”方法如下:
def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
"""Constructor. May be extended, do not override."""
BaseServer.__init__(self, server_address, RequestHandlerClass)
self.socket = socket.socket(self.address_family,
self.socket_type)
if bind_and_activate:
try:
self.server_bind()
self.server_activate()
except:
self.server_close()
raise
3个参数需要传递:1,服务器的IP地址与端口,2,RequestHandlerClass.3,默认设置为True,所以基本不用管,这也是为什么在写代码的时候。socketserver.ThreadingTCPServer((“127.0.0.1”,9200),MyServer)
- 在步骤4中的代码,将“BaseServer.init(self, server_address, RequestHandlerClass)”将传入的参数交给了父类的“__init__()”方法进行处理,所以先查看父类的这个方法是如何处理这两个数据的。
def __init__(self, server_address, RequestHandlerClass):
"""Constructor. May be extended, do not override."""
self.server_address = server_address
self.RequestHandlerClass = RequestHandlerClass
self.__is_shut_down = threading.Event()
self.__shutdown_request = False
* 将传入的服务器的IP地址交给定义的对象,是一个赋值的过程
* 会话的RequestHandlerClass类定义为对象的处理请求的类,是一个赋值的过程
* 后两个先不用考虑
- 再执行第4步骤中的“self.socket = socket.socket(self.address_family, self.socket_type)” 创建了一个套接字,第一个参数为address_family,为对象的地址族,第二个参数为套接字的类型,这两个参数在源码中有默认的定义:
address_family = socket.AF_INET
socket_type = socket.SOCK_STREAM
到此,套接字创建完成。
- 再执行步骤4中的剩下的代码:
if bind_and_activate:
try:
self.server_bind()
self.server_activate()
except:
self.server_close()
raise
如果“bind_and_activate‘为True的情况下(默认为True),self.server_bind() 绑定,self.server_activate()激活
def server_bind(self):
"""Called by constructor to bind the socket.
May be overridden.
"""
if self.allow_reuse_address:
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind(self.server_address)
self.server_address = self.socket.getsockname()
def server_activate(self):
"""Called by constructor to activate the server.
May be overridden.
"""
self.socket.listen(self.request_queue_size)
如果有错误的话,则关闭server,并报一个错。
- 至此,已经创建了套接字,并绑定在了提供的服务器的IP地址与端口上。
- 从这里开始执行的是“server.serve_forever()”
- server是通过类创建的一对象,现在执行的是对象里面的serve_forever() 方法
- 查看源码:
def serve_forever(self, poll_interval=0.5):
"""Handle one request at a time until shutdown.
Polls for shutdown every poll_interval seconds. Ignores
self.timeout. If you need to do periodic tasks, do them in
another thread.
"""
self.__is_shut_down.clear()
try:
# XXX: Consider using another file descriptor or connecting to the
# socket to wake this up instead of polling. Polling reduces our
# responsiveness to a shutdown request and wastes cpu at all other
# times.
with _ServerSelector() as selector:
selector.register(self, selectors.EVENT_READ)
while not self.__shutdown_request:
ready = selector.select(poll_interval)
# bpo-35017: shutdown() called during select(), exit immediately.
if self.__shutdown_request:
break
if ready:
self._handle_request_noblock()
self.service_actions()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
- self.__is_shut_down.clear()
- 将程序运行起来