欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python使用socketServer包搭建簡(jiǎn)易服務(wù)器過(guò)程詳解

 更新時(shí)間:2020年06月12日 09:45:01   作者:沒(méi)有想象力  
這篇文章主要介紹了Python使用socketServer包搭建簡(jiǎn)易服務(wù)器過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

官方提供了socketserver包去方便我們快速的搭建一個(gè)服務(wù)器框架。

server類

socketserver包提供5個(gè)Server類,這些單獨(dú)使用這些Server類都只能完成同步的操作,他是一個(gè)單線程的,不能同時(shí)處理各個(gè)客戶端的請(qǐng)求,只能按照順序依次處理。

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

兩個(gè)Mixin類

+--------------+    +----------------+
| ForkingMixIn |    | ThreadingMixIn |
+--------------+    +----------------+

各自實(shí)現(xiàn)了多進(jìn)程和多線程的功能(ForkingMixIn在Windows不支持)

于是將這些同步類和Mixin類組合就實(shí)現(xiàn)了異步服務(wù)類的效果。

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

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

基本使用

由于server需要同時(shí)處理來(lái)自多個(gè)客戶端的請(qǐng)求,需要提供異步的支持,所以通常使用上面的異步類創(chuàng)建服務(wù)器。在Windows系統(tǒng)中沒(méi)有提供os.fork()接口,Windows無(wú)法使用多進(jìn)程的ForkingUDPServer和ForkingTCPServer,只能使用ThreadingTCPServer或者ThreadingUDPServer;而Linux和Unix多線程和多進(jìn)程版本都可以使用。

服務(wù)器主要負(fù)責(zé)接受客戶端的連接請(qǐng)求,當(dāng)一個(gè)新的客戶端請(qǐng)求到來(lái)后,將分配一個(gè)新的線程去處理這個(gè)請(qǐng)求(異步服務(wù)器ThreadingTCPServer),而與客戶端信息的交互則交給了專門的請(qǐng)求處理類(RequestHandlerClass)處理。

import socketserver
# 創(chuàng)建一個(gè)基于TCP的server對(duì)象,并使用BaseRequestHandler處理客戶端發(fā)送的消息
server = socketserver.ThreadingTCPServer(("127.0.0.1", 8000), BaseRequestHandler) 
server.serve_forever() # 啟動(dòng)服務(wù)器,

只需要上面兩行代碼就可以創(chuàng)建開啟一個(gè)服務(wù),運(yùn)行上面代碼后??幢緳C(jī)8000端口,發(fā)現(xiàn)有程序正在監(jiān)聽。

C:\Users\user>netstat -anp tcp | findstr 8000
TCP 127.0.0.1:8000 0.0.0.0:0 LISTENING

ThreadingTCPServer可以對(duì)我們的請(qǐng)求進(jìn)行接受,但是并不會(huì)進(jìn)行處理請(qǐng)求,處理請(qǐng)求的類是上面指定BaseRequestHandler類,該類可以定義handle方法來(lái)處理接受的請(qǐng)求。

BaseRequestHandler的源碼

class BaseRequestHandler:

  def __init__(self, request, client_address, server):
    self.request = request
    self.client_address = client_address
    self.server = server
    self.setup()
    try:
      self.handle()
    finally:
      self.finish()
  def setup(self):
    pass

  def handle(self):
    pass

  def finish(self):
    pass

在server = socketserver.ThreadingTCPServer(("127.0.0.1", 8000), BaseRequestHandler)中,BaseRequestHandler將作為參數(shù)綁定到服務(wù)器的實(shí)例上,服務(wù)器啟動(dòng)后,每當(dāng)有一個(gè)新的客戶端接接入服務(wù)器,將會(huì)實(shí)例化一個(gè)請(qǐng)求處理對(duì)象,并傳入三個(gè)參數(shù),request(連接客戶端的socket)、client_address(遠(yuǎn)程客戶端的地址)、server(服務(wù)器對(duì)象),執(zhí)行init方法,將這三個(gè)參數(shù)保存到對(duì)應(yīng)屬性上。這個(gè)請(qǐng)求處理對(duì)象便可以與客戶端交互了。

簡(jiǎn)單示例

import socketserver
import threading 

class MyRequestHandler(socketserver.BaseRequestHandler):
  """ BaseRequestHandler的實(shí)例化方法中,獲得了三個(gè)屬性
  self.request = request  # 該線程中與客戶端交互的 socket 對(duì)象。
  self.client_address   # 該線程處理的客戶端地址
  self.server = server   # 服務(wù)器對(duì)象
  """

  def handle(self):
    while True:
      msg = self.request.recv()  # 接受客戶端的數(shù)據(jù)
      if msg == b"quit" or msg == "": # 退出
        break

      print(msg.decode())
      self.request.send(msg) # 將消息發(fā)送回客戶端
  def finish(self):
    self.request.close()    # 關(guān)閉套接字
if __name__ == "__main__":
  # 創(chuàng)建一個(gè)基于TCP的server對(duì)象,并使用BaseRequestHandler處理客戶端發(fā)送的消息
  server = socketserver.ThreadingTCPServer(("127.0.0.1", 8000), MyRequestHandler)

  server.serve_forever()  # 啟動(dòng)服務(wù)器

我們創(chuàng)建了一個(gè)ThreadingTCPServer服務(wù)器,然后在傳入的處理類MyRequestHandler,并在handle方法中提供與客戶端消息交互的業(yè)務(wù)邏輯,此處只是將客戶端的消息返回客戶端。最后我們?cè)趂inish方法中關(guān)閉資源,finish方法使用了finally機(jī)制,保證了這些代碼一定會(huì)執(zhí)行。

上一篇使用socket實(shí)現(xiàn)了一個(gè)群聊服務(wù)器,這個(gè)里使用socketServer將更加方便的實(shí)現(xiàn)

class MyRequestHandle(BaseRequestHandler):
  clients = {} # 在類屬性中記錄所有與客戶端連接socket。
  lock = threading.Lock() # 互斥鎖,各個(gè)線程共用

  def setup(self): # 新的用戶連接時(shí),預(yù)處理,將這個(gè)新的連接加入到clients中,考慮線程安全,需要加鎖
    with self.lock:
      self.clients[self.client_address] = self.request

  def handle(self): # 處理客戶端的請(qǐng)求主邏輯
    while True:
      data = self.request.recv(1024).strip()  # 接受數(shù)據(jù)

      if data == b"quit" or data == b"": # 客戶端退出
        with self.lock:
          self.server.clients.pop(self.client_address)
          self.request.close()
          break

      print("{}-{}: {}".format(*self.client_address, data.decode()))

      with self.lock:
        for _, c in self.server.clients.items(): # 群發(fā)
          c.send(data)
  def finish(self):
    with server.lock:
      for _, c in server.clients.items():
        c.close()
    server.server_close()def main():
  server = ThreadingTCPServer(("127.0.0.1", 8000), MyRequestHandle)
  # 將創(chuàng)建的所有線程設(shè)置為daemon線程,這樣控臺(tái)主程序退出時(shí),這個(gè)服務(wù)器的所有線程將會(huì)被結(jié)束
  server.daemon_threads = True 

if __name__ == "__main__":
  main()

上面requestHandlerclass中的handle方法和finish方式對(duì)應(yīng)了上一篇中TCP服務(wù)器的recv方法和stop方法,他們處理請(qǐng)求的邏輯是相同的。只是上面使用了socketserver的代碼變少了,處理的邏輯也變少了,TCPserver幫我們完成了大量的工作,這利于軟件的快速開發(fā)。

內(nèi)置的兩個(gè)RequestHandlerClass

StreamHandlerRequest

StreamHandlerRequest顧名思義是一種流式的求情處理類,對(duì)應(yīng)TCP協(xié)議的面向字節(jié)流的傳輸形式。我們從源代碼分析。(去除了一些次要代碼)

class StreamRequestHandler(BaseRequestHandler):
  rbufsize = -1 # 讀緩存
  wbufsize = 0  # 寫緩存
  timeout = None # 超時(shí)時(shí)間
  # IP/TCP擁塞控制的Nagle算法算法。
  disable_nagle_algorithm = False

  def setup(self): # 實(shí)現(xiàn)了setup,
    self.connection = self.request
    if self.timeout is not None:
      self.connection.settimeout(self.timeout)
    if self.disable_nagle_algorithm:
      self.connection.setsockopt(socket.IPPROTO_TCP,
                    socket.TCP_NODELAY, True)
    
    # 使用 makefile方法獲得了一個(gè)只讀文件對(duì)象 rfile
    self.rfile = self.connection.makefile('rb', self.rbufsize)
    
    # 獲得一個(gè)只寫的文件對(duì)象 wfile
    if self.wbufsize == 0:
      self.wfile = _SocketWriter(self.connection)
    else:
      self.wfile = self.connection.makefile('wb', self.wbufsize)

  def finish(self): # 負(fù)責(zé)將這個(gè) wfile 和 rfile方法關(guān)閉。
    if not self.wfile.closed: 
      try:
        self.wfile.flush()
      except socket.error:
        pass
    self.wfile.close()
    self.rfile.close()

使用StreamRequestHandler方法可以將這個(gè)socket包裝成一個(gè)類文件對(duì)象,方便我們使用一套文件對(duì)象的方法處理這個(gè)socket,它沒(méi)有實(shí)現(xiàn)handle方法,我仍然需要我們實(shí)現(xiàn)。我們可以這樣使用它

class MyHandle(StreamRequestHandler):
  # 如果需要使用setup和finish方法,需要調(diào)用父類方法,否則該方法將會(huì)被覆蓋。
  def setup(self):
    super().setup()
    # 添加自己的需求
  def handle(self):
    # 這里我們可以使用wfile和rfile來(lái)處理socket消息了,例如之前使用self.request.recv()方法等同于self.rfile.read()
    # 而 self.wfile.write 等同于 self.request.send(),在handle方法中完成業(yè)務(wù)邏輯即可

  def finish(self):
    super().finish()

server = ThreadingTCPServer("127.0.0.1", MyHandle)
server.serve_forever()

StreamRequestHandler主要定義了兩個(gè)新的 wfile對(duì)象和rfile對(duì)象,來(lái)分別對(duì)這個(gè)socket進(jìn)行讀寫操作,當(dāng)我們業(yè)務(wù)需要時(shí),比如需要使用文件接口方法時(shí),選擇繼承于StreamRequestHandler構(gòu)建我們自己處理請(qǐng)求類來(lái)完成業(yè)務(wù)邏輯將會(huì)更加的方便。

DatagramRequestHandler

DatagramRequestHandler字面意思是數(shù)據(jù)報(bào)請(qǐng)求處理,也就是基于UDPServer的服務(wù)器才能使用該請(qǐng)求處理類

class DatagramRequestHandler(BaseRequestHandler):

  def setup(self):
    from io import BytesIO
    # udp的self.request包含兩部分(data,socket)它來(lái)自于
    # data, client_addr = self.socket.recvfrom(self.max_packet_size)
    #   return (data, self.socket), client_addr
    # (data, self.socket)就是這個(gè)self.request,在這里將其解構(gòu),data為recvfrom接收的數(shù)據(jù)
    self.packet, self.socket = self.request
    
    # 該數(shù)據(jù)包封裝為 BytesIO,同樣為一個(gè)類文件對(duì)象。
    self.rfile = BytesIO(self.packet)
    self.wfile = BytesIO()

  def finish(self):
    self.socket.sendto(self.wfile.getvalue(), self.client_address)

從源碼可以看出,DatagramRequestHandler將數(shù)據(jù)包封裝為一個(gè)rfile,并實(shí)例化一個(gè)ByteIO對(duì)象用于寫入數(shù)據(jù),寫入的數(shù)據(jù)可以通過(guò)self.socket這個(gè)套接字發(fā)送。這樣可以使用rfile和wfile這兩個(gè)類文件對(duì)象的read或者write接口來(lái)進(jìn)行一些IO方面的操作。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Django中對(duì)通過(guò)測(cè)試的用戶進(jìn)行限制訪問(wèn)的方法

    Django中對(duì)通過(guò)測(cè)試的用戶進(jìn)行限制訪問(wèn)的方法

    這篇文章主要介紹了Django中對(duì)通過(guò)測(cè)試的用戶進(jìn)行限制訪問(wèn)的方法,Django是眾多Python高人氣web框架中最為著名的一個(gè),需要的朋友可以參考下
    2015-07-07
  • Python實(shí)現(xiàn)數(shù)通設(shè)備端口使用情況監(jiān)控實(shí)例

    Python實(shí)現(xiàn)數(shù)通設(shè)備端口使用情況監(jiān)控實(shí)例

    這篇文章主要介紹了Python實(shí)現(xiàn)數(shù)通設(shè)備端口使用情況監(jiān)控的方法,涉及Python針對(duì)設(shè)備監(jiān)控的操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-07-07
  • pymongo為mongodb數(shù)據(jù)庫(kù)添加索引的方法

    pymongo為mongodb數(shù)據(jù)庫(kù)添加索引的方法

    這篇文章主要介紹了pymongo為mongodb數(shù)據(jù)庫(kù)添加索引的方法,涉及Python操作mongodb數(shù)據(jù)庫(kù)的相關(guān)技巧,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下
    2015-05-05
  • 利用python numpy+matplotlib繪制股票k線圖的方法

    利用python numpy+matplotlib繪制股票k線圖的方法

    這篇文章主要介紹了利用python numpy+matplotlib繪制股票k線圖的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • Pandas實(shí)現(xiàn)Dataframe的合并

    Pandas實(shí)現(xiàn)Dataframe的合并

    我們知道,在使用pandas處理數(shù)據(jù)的時(shí)候,往往會(huì)需要合并兩個(gè)或者多個(gè)DataFrame的操作,那么本文就來(lái)介紹一下Pandas實(shí)現(xiàn)Dataframe的合并,感興趣的可以了解一下
    2021-06-06
  • Python 創(chuàng)建守護(hù)進(jìn)程的示例

    Python 創(chuàng)建守護(hù)進(jìn)程的示例

    這篇文章主要介紹了Python 創(chuàng)建守護(hù)進(jìn)程的示例,幫助大家更好的理解和使用python,感興趣的朋友可以了解下
    2020-09-09
  • 使用DataFrame刪除行和列的實(shí)例講解

    使用DataFrame刪除行和列的實(shí)例講解

    下面小編就為大家分享一篇使用DataFrame刪除行和列的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-04-04
  • 淺析Python中的多進(jìn)程編程

    淺析Python中的多進(jìn)程編程

    在這篇文章中,我們將專注于討論P(yáng)ython中的多進(jìn)程編程,例如進(jìn)程的創(chuàng)建、管理和同步,以及一些更高級(jí)的概念,如進(jìn)程池,需要的可以參考一下
    2023-07-07
  • pyqt5簡(jiǎn)介及安裝方法介紹

    pyqt5簡(jiǎn)介及安裝方法介紹

    這篇文章主要介紹了pyqt5簡(jiǎn)介及安裝方法介紹,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • Python裝飾器詳細(xì)介紹

    Python裝飾器詳細(xì)介紹

    這篇文章主要介紹了Python裝飾器詳細(xì)講解,包括裝飾器的功能及實(shí)現(xiàn)方法,通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-03-03

最新評(píng)論