Python socketserver 伺服器端網路通訊程式

本篇介紹如何使用 Python 3 提供的 socketserver 類別來撰寫 Server 伺服器端的程式,在上一篇介紹了怎麼撰寫一個基本的 TCP socket 通訊程式
這一篇將專門介紹 server 伺服器端的撰寫,為什麼呢?因為通常伺服器端的程式是比客戶端的程式還要難的,
所以 python 提供了 socketserver 這個模組來簡化這個開發的難易度,
而 python 的 socketserver 模組提供了 TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer 這4種,
接下來的內容將會先以 TCP 解說為優先,本篇學習了 socketserver 基礎概念後下篇會以本篇為基礎撰寫一個簡單的聊天程式,

使用 socketserver.TCPServer

以下使用 socketserver.TCPServer 的範例,client 端可以沿用之前的範例,
範例中直接實例化 socketserver.TCPServerMyTCPHandler 繼承 socketserver.BaseRequestHandler
socketserver.BaseRequestHandler 是用來處理接收資料時事件處理,不能直接產生實例,需要繼承 socketserver.BaseRequestHandler 後才能實例化,
handle() 裡撰寫接收後的程式邏輯即可,以這個範例為例,接收到一個 request 後,就開始一個迴圈來交換傳遞資料,

另外補充一下python 2與python 3的差異處,
python 2 是 SocketServer class 與 import SocketServer
python 3 是 socketserver class 與 import socketserver

python3-socketserver-echo-server.py
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
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import socketserver

class MyTCPHandler(socketserver.BaseRequestHandler):

def handle(self):
print('connected by ' + str(self.client_address))
while True:
indata = self.request.recv(1024).strip()
if len(indata) == 0: # connection closed
self.request.close()
print('client closed connection.')
break
print('recv: ' + indata.decode())

outdata = 'echo ' + indata.decode()
self.request.sendall(outdata.encode())

if __name__ == '__main__':
HOST, PORT = "0.0.0.0", 7000

# Create the server, binding to localhost on port 7000
socketserver.TCPServer.allow_reuse_address = True
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)

print('server start at: %s:%s' % (HOST, PORT))
try:
server.serve_forever()
except:
print("closing the server.")
server.server_close()
raise

多執行緒的伺服器端程式

上述的例子一次最多只能服務一個客戶端,這篇介紹用 socketserver.ThreadingMixIn 的方式達成每個連線都建立一個新的執行緒來服務,
進而達成多客戶端連線溝通的例子,
在範例中的 ThreadedTCPServer 是多重繼承 socketserver.ThreadingMixInsocketserver.TCPServer

python3-socketserver-asynchronous-server.py
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
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import socketserver, sys, threading
from time import ctime

class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
cur = threading.current_thread()
print('[%s] Client connected from %s and [%s] is handling with him.' % (ctime(), self.request.getpeername(), cur.name))
while True:
indata = self.request.recv(1024).strip()
if len(indata) == 0: # connection closed
self.request.close()
print('client closed connection.')
break
print('recv: ' + indata.decode())

outdata = 'echo ' + indata.decode()
self.request.send(outdata.encode())

class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
daemon_threads = True
allow_reuse_address = True

if __name__ == '__main__':
HOST, PORT = '0.0.0.0', 7000
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
ip, port = server.server_address
print('server start at: %s:%s' % (HOST, PORT))
try:
server.serve_forever()
except KeyboardInterrupt:
sys.exit(0)

參考
21.21. socketserver — A framework for network servers — Python 3.5.10 documentation
https://docs.python.org/3.5/library/socketserver.html#examples
例項講解Python中SocketServer模組處理網路請求的用法 | 程式前沿
https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/368565/
Python使用SocketServer模組編寫基本伺服器程式的教程 | 程式前沿
https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/368387/
Python socketserver — A framework for network servers | My.APOLLO
https://myapollo.com.tw/zh-tw/python-socketserver/
20.17. SocketServer — A framework for network servers — Python 2 documentation
https://docs.python.org/2/library/socketserver.html
socketserver — A framework for network servers — Python 3 documentation
https://docs.python.org/3/library/socketserver.html

其他相關參考
c# - Why does my python TCP server need to bind to 0.0.0.0 and not localhost or it’s IP address? - Stack Overflow
https://stackoverflow.com/questions/38256851/why-does-my-python-tcp-server-need-to-bind-to-0-0-0-0-and-not-localhost-or-its
Python 3 TypeError: Can’t convert ‘bytes’ object to str implicitly - Mkyong.com
https://mkyong.com/python/python-3-typeerror-cant-convert-bytes-object-to-str-implicitly/

其它相關文章推薦
Python TCP Socket Server/Client 網路通訊程式