103 基於socketserver實現併發的socket編程

1、socketserver模塊

基於tcp的套接字,關鍵就是兩個循環,一個連接循環,一個通訊循環多線程

socketserver模塊中分兩大類:server類(解決連接問題)和request類(解決通訊問題)併發

Server類:socket

server類

request類:tcp

request類

繼承關係:源碼分析

繼承關係1

繼承關係2

繼承關係3

如下述代碼爲例,分析socketserver源碼:線程

ftpserver=socketserver.ThreadingTCPServer(('127.0.0.1',8080),FtpServer)
ftpserver.serve_forever()

查找屬性的順序:ThreadingTCPServer->ThreadingMixIn->TCPServer->BaseServercode

  1. 實例化獲得ftpserver,先找類ThreadingTCPServer的__init__,在TCPServer中找到,進而執行server_bind,server_active
  2. 找ftpserver下的serve_forever,在BaseServer中找到,進而執行self._handle_request_noblock(),該方法一樣是在BaseServer中
  3. 執行self._handle_request_noblock()進而執行request, client_address = self.get_request()(就是TCPServer中的self.socket.accept()),而後執行self.process_request(request, client_address)
  4. 在ThreadingMixIn中找到process_request,開啓多線程應對併發,進而執行process_request_thread,執行self.finish_request(request, client_address)
  5. 上述四部分完成了連接循環,本部分開始進入處理通信部分,在BaseServer中找到finish_request,觸發咱們本身定義的類的實例化,去找__init__方法,而咱們本身定義的類沒有該方法,則去它的父類也就是BaseRequestHandler中找....

1.1 源碼分析總結:

基於tcp的socketserver咱們本身定義的類中的server

  1. self.server即套接字對象
  2. self.request即一個連接
  3.   self.client_address即客戶端地址

基於udp的socketserver咱們本身定義的類中的對象

  1.   self.request是一個元組(第一個元素是客戶端發來的數據,第二部分是服務端的udp套接字對象),如(b'adsf', <socket.socket fd=200, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=('127.0.0.1', 8080)>)
  2.   self.client_address即客戶端地址

2、基於TCP協議

服務端

'''
-tcp的服務端
            -server=ThreadingTCPServer 建立對象
            -server.serve_forever   開線程進行鏈接循環
            -寫一個類(繼承BaseRequestHandler類),類裏重寫handle,方法內收發數據(併發起來了)
'''

#使用socketserver寫服務端
import socketserver

HOST = "127.0.0.1"
PORT = 8080

#本身定義一個類,必須繼承BaseRequestHandler
class MyTcp(socketserver.BaseRequestHandler):
    # 必須重寫handle方法
    def handle(self):
        try:
            while 1:
                # conn對象就是request
                # 接收數據
                print(self.client_address)  # 客戶機地址
                data = self.request.recv(1024)
                print(data.decode("utf8"))
                if len(data) == 0:
                    return
                # 發送數據
                self.request.send(data.upper())
        except:
            print("出錯了")


if __name__ == '__main__':
    # 實例化獲得一個tcp鏈接的對象
    server = socketserver.ThreadingTCPServer((HOST,PORT),MyTcp)
    # 這裏開的線程,獲取鏈接
    server.serve_forever()

客戶端

import socket
soc=socket.socket()

soc.connect(('127.0.0.1',8080))
while True:
    soc.send('你好'.encode('utf-8'))
    print(soc.recv(1024).decode("utf8"))

2、基於UDP協議

服務端

import socketserver

HOST = "127.0.0.1"
PORT = 8081

class MyUDP(socketserver.BaseRequestHandler):
    def handle(self):

        print(self) #  UDP鏈接對象
        # 數據
        print(self.request[0])  # 數據
        print(self.request[1])  # 
        print(type(self.request[1]))

if __name__ == '__main__':
    # 實例化獲得一個tcp鏈接的對象,Threading意思是說,只要來了請求,它自動的開線程來處理鏈接跟交互數據
    server = socketserver.ThreadingUDPServer((HOST,PORT),MyUDP)
    # 一直在等待發送數據來
    server.serve_forever()

客戶端

import socket

HOST = "127.0.0.1"
PORT = 8081

if __name__ == '__main__':
    # 建立對象
    client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    while 1:
        # 發數據
        client.sendto("123123".encode("utf8"),(HOST,PORT))
        # 接收數據
        print(client.recvfrom(1024)[0].decode("utf8"))
相關文章
相關標籤/搜索