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
24
class 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 的子类去实现,如: TCPServerUDPServerget_request() 返回值都不一样。
  • serve_forever() 启动请求服务器

BaseRequestHandler 基类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class 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
2
3
4
5
6
7
8
9
10
11
12
host = '127.0.0.1'
port = 8000
buff_size = 1024
sock = socket.socket()
sock.bind((host, port))
sock.listen(5)
conn, address = sock.accept()
while True:
data = conn.recv(buff_size)
if data:
print(data)
conn.sendall(data.upper())

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
45
class 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
7
class 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
4
host = '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
2
3
4
5
6
7
8
9
10
host = 'localhost'
port = 8080
sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
sock.bind((host, port))
while True:
data, address = sock.recvfrom(1024)
if data:
print('%s:%s - %s' % (address[0], address[1], data))
# return upper data
sock.sendto(data.upper(), address)

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
21
class 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
8
class 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
4
host = 'localhost'
port = 8080
server = socketserver.UDPServer((host, port), UDPHandler)
server.serve_forever()


多进程/多线程处理请求

socketserver 模块提供了 ForkingMixInThreadingMixIn 类来处理请求。

  • ForkingMixIn 会创建一个子进程来处理每个请求
  • ThreadingMixIn 会创建一个线程来处理每个请求

多进程/多线程处理请求的 Server 类

1
2
3
4
5
class ForkingUDPServer(ForkingMixIn, UDPServer): pass
class ForkingTCPServer(ForkingMixIn, TCPServer): pass

class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass

这些 Server 类的用法和 TCPServer, UDPServer 是一样的,只是它们处理请求的机制改变了而已。