1. 程式人生 > 實用技巧 >網路程式設計之併發網路程式設計

網路程式設計之併發網路程式設計

之前使用socket模組實現的網路程式設計都不能併發進行連線和通訊的, 即一個客戶端需要等待伺服器和另一個客戶端通訊完成後才能和服務端進行連線和通訊。

python3中提供有一個高階內建模組socketserver來幫助我們進行併發的網路程式設計。

socketserver模組介紹

SocketServer模組處理網路請求的功能,可以通過兩個主要的類來實現:一個是伺服器類,一個是請求處理類。
伺服器類 處理通訊問題,如監聽一個套接字並接收連線等;

請求處理類 處理“協議”問題,如解釋到來的資料、處理資料並把資料發回給客戶端等。

這種實現將伺服器的實現過程和請求處理的實現過程解耦,這意味著我們可以將不同的伺服器實現和請求處理實現結合起來來處理一些定製的協議,例如一個TCP伺服器類和一個流請求處理類結合,處理基於TCP的網路請求。同時,也可以基於SocketServer模組中的伺服器類和請求處理類,實現網路層之上應用層的伺服器和請求處理實現,例如基於TCP伺服器類實現HTTP伺服器,基於流處理請求類實現HTTP請求處理類等。

SocketServer模組中定義了五種伺服器類

  • BaseServer(伺服器的基類,定義了API)
  • TCPServer(使用TCP/IP套接字)
  • UDPServer(使用資料報套接字)
  • UnixStreamServer(使用UNIX域套接字,只適用UNIX平臺)
  • UnixDatagramServer(使用UNIX域套接字,只適用UNIX平臺)

SocketServer模組中定義了兩種Mixin類, 用於支援非同步(Fork用於建立多程序, Thread使用者建立多執行緒)

  • ForkingMixIn
  • ThreadingMixIn

SocketServer模組伺服器類與Mixin類組合得到

  • class ForkingUDPServer(ForkingMixIn,UDPServer):pass
  • class ForkingTCPServer(ForkingMixIn,TCPServer):pass
  • class ThreadingUDPServer(ThreadingMixIn,UDPServer):pass
  • class ThreadingTCPServer(ThreadingMixIn,TCPServer):pass

建立TCP服務端

import socketserver


ADDR = ('127.0.0.1', 8080)  
  
class MyRequestHandler(socketserver.BaseRequestHandler):
    
def handle(self): print(self.request) # 套接字物件 print(self.client_address) # 客戶端的地址資訊 self.request.close() tcpServer = socketserver.TCPServer(ADDR, MyRequestHandler) tcpServer.serve_forever()

我們從socketserver的BaseRequestHandler類中派生出一個子類,並重寫handle()函式。在BaseRequest 類中,這個函式什麼也不做。在有客戶訊息進來的時候,handle()函式就會被呼叫。

建立UDP服務端

import socketserver


ADDR = ('127.0.0.1', 8080)  
  
class MyRequestHandler(socketserver.BaseRequestHandler):
    def handle(self):
        print(self.request[0])  # 客戶端傳送的訊息
        print(self.request[1])  # 套接字鍍錫
        print(self.client_address)

        self.request.close()
    
  
  
tcpServer = socketserver.UDPServer(ADDR, MyRequestHandler)  
  
tcpServer.serve_forever()

如果要處理多連線問題,那麼有三種主要的方法能實現這個目的:分叉(forking)、執行緒(threading)以及非同步I/O(asynchronous I/O)。通過對socketserver伺服器使用混入類(mix-in class),派生程序和執行緒很容易處理。即使要自己實現它們,這些方法也很容易使用。它們確實有缺點:分叉佔據資源,並且如果有太多的客戶端時分叉不能很好分叉(儘管如此,對於合理數量的客戶端,分叉在現代的UNIX或者Linux系統中是很高效的,如果有一個多CPU系統,那系統效率會更高);執行緒處理能導致同步問題。使用socketserver框架建立分叉或者執行緒伺服器非常簡單

建立TCP分叉服務端

import socketserver


ADDR = ('127.0.0.1', 8889)


class Server(socketserver.ForkingMixIn, socketserver.TCPServer):
    pass


class MyRequestHandler(socketserver.BaseRequestHandler):
    def handle(self):
        print(self.request)
        print(self.client_address)


tcpServer = Server(ADDR, MyRequestHandler)
tcpServer.serve_forever()

建立udp分叉服務端同理即可

建立TCP多程序服務端

import socketserver


ADDR = ('127.0.0.1', 8889)


class Server(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass


class MyRequestHandler(socketserver.BaseRequestHandler):
    def handle(self):
        print(self.request)
        print(self.client_address)


tcpServer = Server(ADDR, MyRequestHandler)
tcpServer.serve_forever()

建立udp多程序服務端同理即可

注意:

ThreadingUDPServer與ThreadingTCPServer類中的特有屬性:

  • daemon_threads=False #預設值是False表示建立的執行緒都不是daemon執行緒,改為True表示建立的所有執行緒都是daemon執行緒
  • block_on_close=False #預設值為Fasle,如果為True,可以設定為守護執行緒