Python - Socket Server
SocketServer/socketserver
Python3,
SocketServer
模块重命名为socketserver
。
socketserver 模块提供了创建网络服务器的简洁的接口。
BaseServer 基类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24class BaseServer:
def __init__(self, server_address, RequestHandlerClass):
self.server_address = server_address
self.RequestHandlerClass = RequestHandlerClass
...
def get_request(self): pass
def finish_request(self, request, client_address):
self.RequestHandlerClass(request, client_address, self)
def process_request(self, request, client_address)
self.finish_request(request, client_address)
self.shutdown_request(request)
def server_activate(self): pass
def serve_forever(self, poll_interval=0.5): pass
def close_request(self, request): pass
def shutdown_request(self, request): pass
...
BaseServer()
初始化必须传递服务器地址((host, port)
) 和处理器类(RequestHandlerClass
的子类)- Server 类最终处理请求的时候是调用 Handler 类去实现的
get_request()
会返回一个二元组(request, client_address)
,传递给 Handler 类。不过这些都是 Server 的子类去实现,如:TCPServer
和UDPServer
的get_request()
返回值都不一样。serve_forever()
启动请求服务器
BaseRequestHandler 基类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class BaseRequestHandler:
def __init__(self, request, client_address, server):
self.request = request
self.client_address = client_address
self.server = server
self.setup()
try:
self.handle()
finally:
self.finish()
def setup(self): pass
def handle(self): pass
def finish(self): pass
Server 子类会调用 Handler 子类来处理请求 process_request
。
request
: Server 子类get_request()
方法返回的第一个参数。- TCPServer: 为接受当前请求的 socket 对象;
- UDPServer: 为接收数据和 socket 对象的二元组
(data, socket)
。
client_address
: Server 子类get_request()
方法返回的第二个参数,为 socket 客户端地址,如:TCP/UDP ->(host, port)
- 处理器主要通过
handle()
方法来处理请求。 - 在
handle()
之前通过setup()
方法来初始化工作。 - 最终通过
finish()
方法来做结束处理工作。
socket 实现 TCP 服务器
1 | host = '127.0.0.1' |
socketserver 实现 TCP 服务器
socketserver 模块可以通过 TCPServer()
来实现 TCP 服务器。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45class TCPServer(BaseServer):
address_family = socket.AF_INET
socket_type = socket.SOCK_STREAM
request_queue_size = 5
allow_reuse_address = False
def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
BaseServer.__init__(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
def server_bind(self):
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):
self.socket.listen(self.request_queue_size)
def server_close(self):
self.socket.close()
def get_request(self):
return self.socket.accept()
def fileno(self):
return self.socket.fileno()
def shutdown_request(self, request):
try:
request.shutdown(socket.SHUT_WR)
except socket.error:
pass #some platforms may raise ENOTCONN here
self.close_request(request)
def close_request(self, request):
request.close()
__init__(self, server_address, RequestHandlerClass, bind_and_activate=True)
server_address
: 服务器地址(host, port)
。RequestHandlerClass
: Handler 类,Server 类处理请求实际上是调用了该类。bind_and_activate
: True/False。 如果为True
,将自动调用self.server_bind()
和self.server_activate()
来绑定并监听服务器。
get_request(self)
返回一个二元组(request, client_address)
,传递给 Handler 类。这里 TCPServer 直接返回socket.accept()
的返回值。
所以,Handler 子类中的self.request
为当前连接的新 socket 对象;self.client_address
为 socket 客户端的地址((host, port)
)。
首先,要定义一个处理TCP请求的 Handler 子类。1
2
3
4
5
6
7class TCPHandler(socketserver.BaseRequestHandler):
def handle(self):
data = self.request.recv(1024)
if data:
print('%s:%s - %s' % (self.address_client[0], self.address_client[1], data))
# return the upper data
self.request.sendall(data.upper())
用 TCPServer 实现 TCP 服务器:1
2
3
4host = 'localhost'
port = 8080
server = socketserver.TCPServer((host, port), TCPHandler)
server.serve_forever()
Python3.6 以上可以用
with
statement context manager
1
2 with socketserver.TCPServer((host, port), TCPHandler) as server:
server.serve_forever()
socket 实现 UDP 服务器
1 | host = 'localhost' |
socketserver 实现 UDP 服务器
socketserver 模块提供了一个 Server 子类 UDPServer
来实现 UDP 服务器。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21class UDPServer(TCPServer):
allow_reuse_address = False
socket_type = socket.SOCK_DGRAM
max_packet_size = 8192
def get_request(self):
data, client_addr = self.socket.recvfrom(self.max_packet_size)
return (data, self.socket), client_addr
def server_activate(self):
# No need to call listen() for UDP.
pass
def shutdown_request(self, request):
# No need to shutdown anything.
self.close_request(request)
def close_request(self, request):
# No need to close anything.
pass
UDPServer 子类继承了 TCPServer。但是要注意 get_request()
返回与 TCPServer 不同。因此,Handler 子类的 self.request
为 (data, socket)
的二元组。
同样,定义一个 Handler 子类1
2
3
4
5
6
7
8class UDPHandler(BaseRequestHandler):
def handle(self):
data, sock = self.request
if data:
print('%s:%s - %s' % (self.client_address[0],
self.client_address[1], data))
sock.sendto(data.upper(), self.client_address)
用 UDPServer 实现 UDP 服务器1
2
3
4host = 'localhost'
port = 8080
server = socketserver.UDPServer((host, port), UDPHandler)
server.serve_forever()
多进程/多线程处理请求
socketserver 模块提供了 ForkingMixIn
和 ThreadingMixIn
类来处理请求。
ForkingMixIn
会创建一个子进程来处理每个请求ThreadingMixIn
会创建一个线程来处理每个请求
多进程/多线程处理请求的 Server 类1
2
3
4
5class ForkingUDPServer(ForkingMixIn, UDPServer): pass
class ForkingTCPServer(ForkingMixIn, TCPServer): pass
class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
这些 Server 类的用法和 TCPServer
, UDPServer
是一样的,只是它们处理请求的机制改变了而已。