Socketserver模塊

1.socketserver介紹

socketserver是標準庫中的一個高級模塊,socketserver模塊是python提供的內置的用於快捷開發服務端程序的一個服務器框架,通過封裝大量實現的方式減少開發人員工作量的同時能快捷開發出具有較高質量的服務端程序;

該模塊中類的繼承關係如下:

 +------------+
| BaseServer |
+------------+
|
v
+-----------+ +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+ +------------------+
|
v
+-----------+ +--------------------+
| UDPServer |------->| UnixDatagramServer |
+-----------+ +--------------------+

socketserver模塊主要包含的非Unix服務器類有:TCPserver、UCPserver、ThreadingTCPServer(ThreadingMixIn, TCPServer)、ThreadingUDPServer(ThreadingMixIn, UDPServer)、ForkingTCPServer(ForkingMixIn, TCPServer)、ForkingUDPServer(ForkingMixIn, UDPServer),其中的ThreadingMixIn、ForkingMixIn分別用來實現線程級別、進程級別的異步

2.Socketserver模塊四個基本的服務器類分別是:

  • TCPServer,基本的網絡同步TCP服務器;
  • UDPServer
    ,基本的網絡同步UDP服務器;
  • UnixStreamServer,使用UNIX域套接字實現面向數據流協議的服務器,繼承自TCPServer;
  • UnixDatagramServer,使用UNIX域套接字實現數據報協議的服務器,繼承自UDPServer;

其中常用的是TCPServer和UDPServer,且這四個類型都是同步地處理請求,也就是說一個請求沒有完成之前是不會處理下一個請求的,但是這種模式不適合生產環境。

所以這個模塊還提供了兩種支持異步處理的類,ForkingMixIn和ThreadingMixIn,繼承自這兩個類的服務端在處理新的客戶端連接時不會阻塞,而是創建新的進程或線程來專門處理客戶端的請求:

  • ForkingMixIn,將UNIX進程分支添加到服務器的混合方法,使用該方法可以讓服務器服務多個客戶,(為每一個客戶端請求派生一個新的進程去專門處理);
  • ThreadingMixIn,修改服務器的混合類,可以使用多線程服務多個客戶端,(為每一個客戶端請求派生一個新的線程去專門處理);

3.如何使用socketserver編寫服務器端

我們先編寫服務器端的代碼,首先導入了socketserver模塊,然後自定義一個Handler類,這個類是繼承了socketserver模塊中的BaseRequestHandler。

我們可以按住Ctrl鍵然後鼠標點擊這個類,看一下這個類的方法有哪些,除了一個__init__()方法,是不是還有三個沒有實現的setup()、handle()、finish()方法呀,那這裡就在Handler類中覆蓋BaseRequestHandler類的handle()方法,打印一些信息。

然後選擇一個合適的Server類,初始化且綁定地址和新建的Handler處理類,最後調用server實例的serve_forever()方法,啟動server。

import socketserver
import threading
from pprint import pprint
class Handler(socketserver.BaseRequestHandler):
def handle(self):
print('當前的server類型: {}'.format(self.server))
print('當前的socket連接對象: {}'.format(self.request))
print('當前的客戶端地址: {}'.format(self.client_address))
print('線程列表: {}'.format(threading.enumerate()))
print('當前的線程:{}'.format(threading.current_thread()))
server = socketserver.TCPServer(('127.0.0.1', 9000), Handler)
server.serve_forever()

我們運行一下這個代碼,發現控制檯並沒有輸出,那我們可以到命令窗口查看一下TCP是否連接,命令行為:netstat -anp tcp | grep 9000,然後顯示的是正在監聽並沒有連接,我們可以直接使用瀏覽器請求9000端口,因為HTTP是在TCP之上實現的一種協議,然後在瀏覽器中訪問127.0.0.1: 9000,控制檯中打印出很多的信息:


Socketserver模塊

命令.png



當前的server類型: <socketserver.tcpserver>
當前的socket連接對象: <socket.socket>
當前的客戶端地址: ('127.0.0.1', 63944)
線程列表: [<_mainthread started="">]
當前的線程:<_mainthread started="">
當前的server類型: <socketserver.tcpserver>
當前的socket連接對象: <socket.socket>
當前的客戶端地址: ('127.0.0.1', 63945)
線程列表: [<_mainthread started="">]
當前的線程:<_mainthread started="">
當前的server類型: <socketserver.tcpserver>
當前的socket連接對象: <socket.socket>
當前的客戶端地址: ('127.0.0.1', 63948)
線程列表: [<_mainthread started="">]
當前的線程:<_mainthread started="">
當前的server類型: <socketserver.tcpserver>
當前的socket連接對象: <socket.socket>
當前的客戶端地址: ('127.0.0.1', 63949)
線程列表: [<_mainthread started="">]
當前的線程:<_mainthread started="">
當前的server類型: <socketserver.tcpserver>

當前的socket連接對象: <socket.socket>
當前的客戶端地址: ('127.0.0.1', 63950)
線程列表: [<_mainthread started="">]
當前的線程:<_mainthread started="">
當前的server類型: <socketserver.tcpserver>
當前的socket連接對象: <socket.socket>
當前的客戶端地址: ('127.0.0.1', 63951)
線程列表: [<_mainthread started="">]
當前的線程:<_mainthread started="">
/<socket.socket>/<socketserver.tcpserver>/<socket.socket>/<socketserver.tcpserver>/<socket.socket>/<socketserver.tcpserver>/<socket.socket>/<socketserver.tcpserver>/<socket.socket>/<socketserver.tcpserver>/<socket.socket>/<socketserver.tcpserver>

那我們總結一下,socketserver模塊創建服務器步驟

  • 第一步:創建一個請求處理類繼承於BaseRequestHandler類, 且覆蓋父類的handler方法,重寫的這個方法會處理傳入的請求;
  • 第二步: 實例化一個服務器類,傳遞這個服務器的地址和你第一步創建的請求處理類到你實例化的服務器;
  • 第三步: 調用server實例的serve_forever()方法(可以處理多個請求)或者handle_request()方法(只處理一個請求)來處理服務器中的一個或者多個請求; 最後調用server_close()來關閉socket鏈接;

4.BaseRequestHandle類的方法介紹

  • setup():該方法在handle()之前調用,默認什麼都不做,如果希望服務器實現更多連接設置,則無需調用該方法;
  • handle():調用該方法執行實際的請求操作,調用函數可以不帶任何參數,默認什麼都不做;
  • finish(): 環境清理,在handle()之後執行清除操作,默認什麼都不做,如果setup()和handle()方法都不生成異常,則無需調用該方法;

7.多客戶端的socketserver實現

############################## 服務器端 ##############################
import socketserver

import threading

class Handler(socketserver.BaseRequestHandler):
clients = {}
def setup(self):
super().setup()
self.event = threading.Event()
self.clients[self.client_address] = self.request

def handle(self):
super().setup()
while not self.event.is_set():
data = self.request.recv(1024).decode()
if data == 'quit':
break
msg = "{} 說 {}".format(self.client_address, data).encode()
print(self.clients)
if self.client_address in self.clients.keys():
self.clients[self.client_address].send(msg)
# if request self.clients.values():
# request.send(msg)
print('server end')

def finish(self):
super().finish()
self.clients.pop(self.client_address)
self.event.set()


if __name__ == '__main__':
server = socketserver.ThreadingTCPServer(('127.0.0.1', 9000), Handler)
threading.Thread(target=server.serve_forever, daemon=True).start()
while True:
cmd = input('請輸入您想說的話: ').strip()
if cmd == 'quit':
print(cmd)
server.shutdown()
server.server_close()
break
else:
print('您可以輸入quit來停止服務器! ')

############################## 客戶端 ##############################
import socket

# 創建TCP連接

socket_instance = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_instance.connect(('127.0.0.1', 9000))

while True:
cmd = input("請輸入您想說的話:")
socket_instance.send(cmd.encode())
data = socket_instance.recv(1024).decode()
print(data)


分享到:


相關文章: