socketserver多線程處理


一、簡介

  SocketServer簡化了網絡服務器的編寫。在進行socket創建時,使用SocketServer會大大減少創建的步驟,並且SocketServer使用了select它有5個類:BaseServer,TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer。后4個類是同步進行處理的,另外通過ForkingMixIn和ThreadingMixIn類來支持異步。

  SocketServer的5個類的繼承關系

 

  SocketServer內部使用 IO多路復用 以及 “多線程” 和 “多進程” ,從而實現並發處理多個客戶端請求的Socket服務端。即:每個客戶端請求連接到服務器時,Socket服務端都會在服務器是創建一個“線程”或者“進 程” 專門負責處理當前客戶端的所有請求。

  

二、提供的類型

   一是Server類:BaseServer/TCPServer/UDPServer用來接收客戶的請求。TCPServer處理TCP請求,UDPServer處理UDP請求。BaserServer是基類,不能直接使用。TCPServer繼承自BaseServer,UDPServer繼承自TCPServer。

  二是Handler類:BaseRequestHandler/DatagramRequestHandler/StreamRequestHandler用來處理每一個客戶請求。一般用使用BaseRequestHandler就行,但StreamRequestHandler/DatagramRequestHandler提供了一些特別的功能,前者用來處理流式(TCP)請求,后者處理數據報(UDP)請求。Server每收到一個客戶請求就會創建一個Handler類示例來處理該請求。默認情況下,TCPServer/UDPServer是單進程單線程的模型,依次處理每個客戶請求,一個請求處理完畢才能接着處理下一個請求。

  三是MixIn類:ForkingMixIn/ThreadingMixIn用來為Server提供多進程/多線程並發處理能力的。ForkingMixIn是多進程模型,ThreadingMixin是多線程模型。這里特別巧妙的是,你只要創建一個類,同時繼承Server類和MixIn類就能自動獲得並發處理請求的能力。該模塊本身就直接提供了這種類。

class ForkingUDPServer(ForkingMixIn, UDPServer): pass
class ForkingTCPServer(ForkingMixIn, TCPServer): pass

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

 

 三、創建socketserver步驟

  • 必須先創建一個請求處理的類,並且這個類要繼承BaseRequestHandle,並重寫父類中的handle方法
  • 實例化一個server class,並且傳遞server ip 和剛創建的請求處理類給server class
  • 調用server class 對象的 handle_request() 或 server_forever()方法來開始處理請求
  • 關閉請求

  server.handle_request()   只處理一個請求

       server.forever()      處理多個請求,一直執行

四、事例

  簡單的接收客戶端發送的信息,並將其轉換成大寫,再返回給客戶端

  服務端: 

# -*- coding: UTF-8 -*-
import socketserver


class MyTCPHandler(socketserver.BaseRequestHandler):
    """
    The request handler class for our server.

    It is instantiated once per connection to the server, and must
    override the handle() method to implement communication to the
    client.
    """

    def handle(self):
        while True:   # 多次接收客戶端信息
            # self.request is the TCP socket connected to the client
            self.data = self.request.recv(1024).strip()
            print("{} wrote:".format(self.client_address[0]))
            print(self.data)
            # just send back the same data, but upper-cased
            self.request.sendall(self.data.upper())

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999

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

    # Activate the server; this will keep running until you
    # interrupt the program with Ctrl-C
    server.serve_forever()

  客戶端:

# -*- coding: UTF-8 -*-

import socket

client = socket.socket()

client.connect(('localhost', 9999))

while True:

    msg = input('>>:').strip()
    if not msg:
        continue
    else:
        client.send(msg.encode('utf-8'))
        upData = client.recv(1024)
        print(upData.decode())

  

五、多線程處理

  到目前為止我們所有的c/s連接都同時只能處理一個客戶端請求,多個客戶端請求時,要等前面的客戶端請求關閉后才能執行,包括上面的代碼也是。如果想讓socketserver並發起來, 必須選擇使用以下一個多並發的類:

class socketserver.ForkingTCPServer

class socketserver.ForkingUDPServer

class socketserver.ThreadingTCPServer

class socketserver.ThreadingUDPServer

  只需要改變一個地方就可以了

server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)

  服務端:

import socketserver


class MyTCPHandler(socketserver.BaseRequestHandler):

    def handle(self):
        while True:
            # self.request is the TCP socket connected to the client
            self.data = self.request.recv(1024).strip()
            print("{} wrote:".format(self.client_address[0]))
            print(self.data)
            # just send back the same data, but upper-cased
            self.request.sendall(self.data.upper())

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999
    server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
    server.serve_forever()

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM