Python使用SocketServer模塊編寫(xiě)基本服務(wù)器程序的教程
SocketServer簡(jiǎn)化了網(wǎng)絡(luò)服務(wù)器的編寫(xiě)。它有4個(gè)類:TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer。這4個(gè)類是同步進(jìn)行處理的,另外通過(guò)ForkingMixIn和ThreadingMixIn類來(lái)支持異步。
創(chuàng)建服務(wù)器的步驟。首先,你必須創(chuàng)建一個(gè)請(qǐng)求處理類,它是BaseRequestHandler的子類并重載其handle()方法。其次,你必須實(shí)例化一個(gè)服務(wù)器類,傳入服務(wù)器的地址和請(qǐng)求處理程序類。最后,調(diào)用handle_request()(一般是調(diào)用其他事件循環(huán)或者使用select())或serve_forever()。
集成ThreadingMixIn類時(shí)需要處理異常關(guān)閉。daemon_threads指示服務(wù)器是否要等待線程終止,要是線程互相獨(dú)立,必須要設(shè)置為T(mén)rue,默認(rèn)是False。
無(wú)論用什么網(wǎng)絡(luò)協(xié)議,服務(wù)器類有相同的外部方法和屬性。
在Python3中,本模塊為socketserver模塊。在Python 2中,本模塊為SocketServer模塊。所以在用import導(dǎo)入時(shí),要分情況導(dǎo)入,否則會(huì)報(bào)錯(cuò)。導(dǎo)入的代碼如下:
try: import socketserver #Python 3 except ImportError: import SocketServer #Python 2
SocketSerror模塊包括許多可以簡(jiǎn)化TCP、UDP、UNIX域套接字 服務(wù)器實(shí)現(xiàn)的類。
一、處理程序
要使用本模塊,必須定義一個(gè)繼承于基類BaseRequestHandler的處理程序類。BaseRequestHandler類的實(shí)例h可以實(shí)現(xiàn)以下方法:
1、h.handle() 調(diào)用該方法執(zhí)行實(shí)際的請(qǐng)求操作。調(diào)用該函數(shù)可以不帶任何參數(shù),但是幾個(gè)實(shí)例變量包含有用的值。h.request包含請(qǐng)求,h.client_address包含客戶端地址,h.server包含調(diào)用處理程序的實(shí)例。對(duì)于TCP之類的數(shù)據(jù)流服務(wù),h.request屬性是套接字對(duì)象。對(duì)于數(shù)據(jù)報(bào)服務(wù),它是包含收到數(shù)據(jù)的字節(jié)字符串。
2、h.setup() 該方法在handle()之前調(diào)用。默認(rèn)情況下,它不執(zhí)行任何操作。如果希望服務(wù)器實(shí)現(xiàn)更多連接設(shè)置(如建立SSL連接),可以在這里實(shí)現(xiàn)。
3、h.finish() 調(diào)用本方法可以在執(zhí)行完handle()之后執(zhí)行清除操作。默認(rèn)情況下,它不執(zhí)行任何操作。如果setup()和handle()方法都不生成異常,則無(wú)需調(diào)用該方法。
如果知道應(yīng)用程序只能操縱面向數(shù)據(jù)流的連接(如TCP),那么應(yīng)從StreamRequestHandler繼承,而不是BaseRequestHandler。StreamRequestHandler類設(shè)置了兩個(gè)屬性,h.wfile是將數(shù)據(jù)寫(xiě)入客戶端的類文件對(duì)象,h.rfile是從客戶端讀取數(shù)據(jù)的類文件對(duì)象。
如果要編寫(xiě)針對(duì)數(shù)據(jù)包操作的處理程序并將響應(yīng)持續(xù)返回發(fā)送方,那么它應(yīng)當(dāng)從DatagramRequestHandler繼承。它提供的類接口與StramRequestHandler相同。
二、服務(wù)器
要使用處理程序,必須將其插入到服務(wù)器對(duì)象。定義了四個(gè)基本的服務(wù)器類。
(1)TCPServer(address,handler) 支持使用IPv4的TCP協(xié)議的服務(wù)器,address是一個(gè)(host,port)元組。Handler是BaseRequestHandler或StreamRequestHandler類的子類的實(shí)例。
(2)UDPServer(address,handler) 支持使用IPv4的UDP協(xié)議的服務(wù)器,address和handler與TCPServer中類似。
(3)UnixStreamServer(address,handler) 使用UNIX域套接字實(shí)現(xiàn)面向數(shù)據(jù)流協(xié)議的服務(wù)器,繼承自TCPServer。
(4)UnixDatagramServer(address,handler) 使用UNIX域套接字實(shí)現(xiàn)數(shù)據(jù)報(bào)協(xié)議的服務(wù)器,繼承自UDPServer。
所有四個(gè)服務(wù)器類的實(shí)例都有以下方法和變量:
1、s.socket 用于傳入請(qǐng)求的套接字對(duì)象。
2、s.sever_address 監(jiān)聽(tīng)服務(wù)器的地址。如元組("127.0.0.1",80)
3、s.RequestHandlerClass 傳遞給服務(wù)器構(gòu)造函數(shù)并由用戶提供的請(qǐng)求處理程序類。
4、s.serve_forever() 處理無(wú)限的請(qǐng)求
5、s.shutdown() 停止serve_forever()循環(huán)
6、s.fileno() 返回服務(wù)器套接字的整數(shù)文件描述符。該方法可以有效地通過(guò)輪詢操作(如select()函數(shù))使用服務(wù)器實(shí)例。
三、定義自定義服務(wù)器
服務(wù)器往往需要特殊的配置來(lái)處理不同的網(wǎng)絡(luò)地址族、超時(shí)期、并發(fā)和其他功能,可以通過(guò)繼承上面四個(gè)基本服務(wù)器類來(lái)自行定義。
可以通過(guò)混合類獲得更多服務(wù)器功能,這也是通過(guò)進(jìn)程或線程分支添加并發(fā)行的方法。為了實(shí)現(xiàn)并發(fā)性,定義了以下類:
(1)ForkingMixIn 將UNIX進(jìn)程分支添加到服務(wù)器的混合方法,使用該方法可以讓服務(wù)器服務(wù)多個(gè)客戶。
(2)ThreadingMixIn 修改服務(wù)器的混合類,可以使用線程服務(wù)多個(gè)客戶端。
要向服務(wù)器添加這些功能,可以使用多重繼承,其中首先列出混了類。
由于并發(fā)服務(wù)器很常用,為了定義它,SocketServer預(yù)定義了以下服務(wù)器類:
(1)ForkingUDPServer(address,handler)
(2)ForkingTCPServer(address,handler)
(3)ThreadingUDPServer(address,handler)
(4)ThreadingTCPServer(address,handler)
上面有點(diǎn)亂,現(xiàn)總結(jié)以下:
SocketServer模塊中的類主要有以下幾個(gè):
1、BaseServer 包含服務(wù)器的核心功能與混合類(mix-in)的鉤子功能。這個(gè)類主要用于派生,不要直接生成這個(gè)類的類對(duì)象,可以考慮使用TCPServer和UDPServer類。
2、TCPServer 基本的網(wǎng)絡(luò)同步TCP服務(wù)器
3、UDPServer 基本的網(wǎng)絡(luò)同步UDP服務(wù)器
4、ForkingMixIn 實(shí)現(xiàn)了核心的進(jìn)程化功能,用于與服務(wù)器類進(jìn)行混合(mix-in),以提供一些異步特性。不要直接生成這個(gè)類的對(duì)象。
5、ThreadingMixIn 實(shí)現(xiàn)了核心的線程化功能,用于與服務(wù)器類進(jìn)行混合(mix-in),以提供一些異步特性。不要直接生成這個(gè)類的對(duì)象。
6、ForkingTCPServer ForkingMixIn與TCPServer的組合
7、ForkingUDPServer ForkingMixIn與UDPServer的組合
8、BaseRequestHandler
9、StreamRequestHandler TCP請(qǐng)求處理類的一個(gè)實(shí)現(xiàn)
10、DataStreamRequestHandler UDP請(qǐng)求處理類的一個(gè)實(shí)現(xiàn)
現(xiàn)在繁雜的事務(wù)都已經(jīng)封裝到類中了,直接使用類即可。
四、實(shí)例
1.使用SocketServer模塊編寫(xiě)的TCP服務(wù)器端代碼:
#! /usr/bin/env python #coding=utf-8 """使用SocketServer來(lái)實(shí)現(xiàn)簡(jiǎn)單的TCP服務(wù)器""" from SocketServer import (TCPServer,StreamRequestHandler as SRH) from time import ctime class MyRequestHandler(SRH): def handle(self): print "connected from ",self.client_address self.wfile.write("[%s] %s" %(ctime(),self.rfile.readline())) tcpSer=TCPServer(("",10001),MyRequestHandler) print "waiting for connection" tcpSer.serve_forever() 相應(yīng)的TCP客戶端代碼: #! /usr/bin/env python #coding=utf-8 from socket import * BUFSIZE=1024 #每次都要?jiǎng)?chuàng)建新的連接 while True: tcpClient=socket(AF_INET,SOCK_STREAM) tcpClient.connect(("localhost",10001)) data=raw_input(">") if not data: break tcpClient.send("%s\r\n" %data) data1=tcpClient.recv(BUFSIZE) if not data1: break print data1.strip() tcpClient.close()
2.異步服務(wù)器的實(shí)現(xiàn)
ThreadingMixIn的例子:
import socketimport threadingimport SocketServerclass ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler): def handle(self): data = self.request.recv(1024) cur_thread = threading.current_thread() response = "{}: {}".format(cur_thread.name, data) self.request.sendall(response)class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): passdef client(ip, port, message): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((ip, port)) try: sock.sendall(message) response = sock.recv(1024) print "Received: {}".format(response) finally: sock.close()if __name__ == "__main__": # Port 0 means to select an arbitrary unused port HOST, PORT = "localhost", 0 server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler) ip, port = server.server_address # Start a thread with the server -- that thread will then start one # more thread for each request server_thread = threading.Thread(target=server.serve_forever) # Exit the server thread when the main thread terminates server_thread.daemon = True server_thread.start() print "Server loop running in thread:", server_thread.name client(ip, port, "Hello World 1") client(ip, port, "Hello World 2") client(ip, port, "Hello World 3") server.shutdown()
執(zhí)行結(jié)果:
$ python ThreadedTCPServer.py Server loop running in thread: Thread-1 Received: Thread-2: Hello World 1 Received: Thread-3: Hello World 2 Received: Thread-4: Hello World 3
相關(guān)文章
Python 批量操作設(shè)備的實(shí)現(xiàn)步驟
本文將結(jié)合實(shí)例代碼,介紹Python 批量操作設(shè)備的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-07-07python實(shí)現(xiàn)逆波蘭計(jì)算表達(dá)式實(shí)例詳解
這篇文章主要介紹了python實(shí)現(xiàn)逆波蘭計(jì)算表達(dá)式的方法,較為詳細(xì)的分析了逆波蘭表達(dá)式的概念及實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-05-05python 3.5實(shí)現(xiàn)檢測(cè)路由器流量并寫(xiě)入txt的方法實(shí)例
這篇文章主要給大家介紹了關(guān)于利用python 3.5實(shí)現(xiàn)檢測(cè)路由器流量并寫(xiě)入txt的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起看看吧。2017-12-12Python常用庫(kù)大全及簡(jiǎn)要說(shuō)明
本文為大家羅列了Python開(kāi)發(fā)的常用庫(kù)和各個(gè)庫(kù)的簡(jiǎn)要說(shuō)明以及Python開(kāi)發(fā)工具,包管理,環(huán)境管理等其它常用資源和Python學(xué)習(xí)資料2020-01-01python實(shí)現(xiàn)MongoDB的雙活示例
本文主要介紹了python實(shí)現(xiàn)MongoDB的雙活示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02Python 寫(xiě)小游戲吃金幣+打乒乓+滑雪(附源碼)
這篇文章主要給大家分享的是利用Python 寫(xiě)小游戲吃金幣、打乒乓、滑雪并附上源碼,具有一的知識(shí)性參考價(jià)值,需要的小伙伴可以參考一下2022-03-03