本篇介紹如何使用 Python 3 提供的 socketserver 類別來撰寫 Server 伺服器端的程式,在上一篇介紹了怎麼撰寫一個基本的 TCP socket 通訊程式,
這一篇將專門介紹 server 伺服器端的撰寫,為什麼呢?因為通常伺服器端的程式是比客戶端的程式還要難的,
所以 python 提供了 socketserver 這個模組來簡化這個開發的難易度,
而 python 的 socketserver 模組提供了 TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer 這4種,
接下來的內容將會先以 TCP 解說為優先,本篇學習了 socketserver
基礎概念後下篇會以本篇為基礎撰寫一個簡單的聊天程式,
使用 socketserver.TCPServer
以下使用 socketserver.TCPServer
的範例,client 端可以沿用之前的範例,
範例中直接實例化 socketserver.TCPServer
與 MyTCPHandler
繼承 socketserver.BaseRequestHandler
,socketserver.BaseRequestHandler
是用來處理接收資料時事件處理,不能直接產生實例,需要繼承 socketserver.BaseRequestHandler
後才能實例化,
在 handle()
裡撰寫接收後的程式邏輯即可,以這個範例為例,接收到一個 request 後,就開始一個迴圈來交換傳遞資料,
另外補充一下python 2與python 3的差異處,
python 2 是 SocketServer
class 與 import SocketServer
python 3 是 socketserver
class 與 import socketserver
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.ThreadingMixIn
與 socketserver.TCPServer
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/