30.4. 企業級開發進階2.4:服務端快捷開發

大牧莫邪發表於2017-05-31

前面的內容中已經介紹了TCP程式設計和UDP程式設計實現網路資料的通訊和共享

我們可以看到客戶端程式的編寫相對容易,主需要連線服務端然後跟服務端進行資料互動就OK了。但是服務端的程式編寫較為複雜,如果考慮到資料的併發處理等各種問題,就更加複雜難以操作了。

python提供了一個socketserver模組,可以用於更加快捷的構建我們需要的服務端環境

本節內容

  1. socketserver模組簡介
  2. 常規模式服務端程式設計
  3. 併發模式服務端程式設計

1. socketserver模組簡介

  • socketserver是什麼? socketserver模組時python提供的內建的用於快捷開發服務端程式的一個伺服器框架,通過封裝大量實現的方式減少開發人員工作量的同時能快捷開發出具有較高質量的服務端程式。

  • socketserver中提供了什麼? socketserver模組主要包含的伺服器類:TCPserver、UCPserver、ThreadingTCPserver、ThreadingUDPserver、ForkingTCPserver、ForkingUDPserver 注意:上述TCP表示TCP服務端程式設計需要的服務類,UDP表示UDP程式設計需要的服務類,包含Threading的表示多執行緒併發需要的服務類;包含Forking的表示多程式併發需要的服務類 關於多執行緒和多程式,後面的章節中會詳細介紹

  • socketserver核心操作? socketserver框架中,服務端的處理類主要有StreamRequestHandler(基於TCP協議的)、DatagramRequestHandler(基於UDP協議的),處理類中非常重要的一個方法headler()用來執行服務端程式中的核心操作 ```

    class mytcpserver(socketserver.StreamRequestHandler): def handle(self): # 伺服器中的核心操作程式碼

```

  • socketserver中的結構? socketserver中主要包含兩部分:伺服器和處理類 服務類就是socketserver提供了內建服務類,如TCPserver、UDPserver等等 處理類就是我們自定義的處理類,處理類中會包含handle()方法用於業務處理

2. 服務端程式設計

2.1. TCP服務端程式設計

使用socketserver編寫服務端程式如下: ```

import socketserver


# 自定義處理類
class myTcp(socketserver.StreamRequestHandler):
    # 定義處理方法
    def handle(self):
        # 通過client_address屬性檢視連線進來的伺服器
        print("連線上的伺服器:%s" % str(self.client_address))
        while True:
            # 接收客戶端傳送的資料
            msg = self.request.recv(1024)
            if not msg:
                break;
            print("客戶端發過來訊息:%s" % msg.decode("UTF-8"))
            # 給客戶端返回接收資訊
            self.request.sendall("已經成功接收您傳送的訊息".encode("UTF-8"))


# 程式從主執行緒直接執行
if __name__ == "__main__":
    # 建立服務端物件,指定處理類,並監聽8888埠
    server = socketserver.TCPServer(('', 8888), myTcp)
    # 啟動服務端程式
    server.serve_forever()

```

此時,我們使用常規模式開發客戶端程式如下: ```

import socket

sc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

sc.connect(("192.168.10.108", 8888))

while True:
    msg = input("請輸入要傳送的內容:")
    if not msg or msg == "exit":
        break
    sc.sendall(msg.encode("UTF-8"))
    msg = sc.recv(1024)
    print("伺服器回應:" + msg.decode("UTF-8"))

sc.close()

```

執行上述程式,就可以和之前一樣,實現客戶端和服務端之間的資料通訊了; 和以前不一樣的時,此時我們如果關閉了客戶端,服務端程式還是在執行的,如果重新啟動客戶端,客戶端又會接入服務端,重新建立連線並通訊。

2.2. UDP服務端程式設計

使用socketserver的UDPServer服務類和DatagramRequestHandler處理類進行服務端的程式設計處理如下: ```

import socketserver

# 建立自定義處理類
class myUdp(socketserver.DatagramRequestHandler):
    # 建立自定義處理方法
    def handle(self):
        # 列印連線進來的客戶端資訊
        print("連線到伺服器的主機:" + str(self.client_address))

        # 收發訊息
        while True:
            # 接收客戶端傳送的訊息
            # msg = self.request.recv()
            msg = self.rfile.readline()
            if not msg:
                break
            print("接受到客戶端傳送的訊息:%s" % msg.decode("UTF-8"))
            # 傳送訊息
            self.wfile.write("接收到您傳送的訊息".encode("UTF-8"))
# 主模組執行緒中執行程式
if __name__ == "__main__":
    # 建立UDP伺服器物件
    server = socketserver.UDPServer(("", 8989), myUdp)
    # 啟動UDP伺服器
    server.serve_forever()

```

使用常規的方式開發UDP客戶端程式碼如下: ```

import socket

sc = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

while True:
    data = input("請輸入要傳送的訊息:")
    if not data or data == "exit":
        break

    sc.sendto(data.encode("UTF-8"), ("192.168.10.108", 8989))

    data,recv = sc.recvfrom(1024)
    if not data:
        break
    print("伺服器返回訊息:" + data.decode("UTF-8"))

sc.close()

```

此時啟動服務端程式,啟動客戶端程式,就可以實現服務端和客戶端時間的資料通訊了。 另外:你可以試試啟動多個客戶端程式看看,有彩蛋哦。

3. 服務端併發

關於使用多執行緒或者多程式併發的方式也是比較簡單的,參考程式碼如下,如果有興趣的話,等學習完併發程式設計之後,可以再回過頭看看ThreadingTCPServer和ForkingTCPServer這樣多執行緒和多程式併發的操作哦 服務端參考程式碼: ```

import socketserver

class myTcp(socketserver.StreamRequestHandler):
    def handle(self):
        while True:
            data = self.request.recv(1024)
            print("接收到資料:" + data.decode("UTF-8"))
            self.request.sendall("資料已經接收成功".encode("UTF-8"))

if __name__ == "__main__":
    server = socketserver.ThreadingTCPServer(("", 9000), myTcp)
    server.serve_forever()

客戶端還是常規的客戶端

import socket

sc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

sc.connect(("192.168.10.108", 9000))

while True:
    msg = input("請輸入要傳送的內容:")
    if not msg or msg == "exit":
        break
    sc.sendall(msg.encode("UTF-8"))
    msg = sc.recv(1024)
    print("伺服器回應:" + msg.decode("UTF-8"))

sc.close()

```

相關文章