WEEK8:Python網絡編程 Socket編程

  • 動態導入模塊
    • 使用python內置方法__import__導入模塊
       1 #環境
       2 #動態導入模塊.py
       3 #lib
       4 #--__pycache__
       5 #--__init__.py
       6 #--aa.py
       7 
       8 #方法一
       9 lib=__import__("lib.aa") #解釋器內部使用
      10 obj=lib.aa.C()
      11 print(obj.name)
      12 #方法二
      13 import importlib
      14 importlib.import_moudle("lib.aa")
      15 print(aa.C().name)
  • 斷言
    • assert斷言語句用來聲明某個條件是真的,其做用是測試一個條件(condition)是否成立,若是不成立,則拋出異常。
    • assert通常用法: assert condition
      等同下面的邏輯:
      若是condition爲false,就raise一個AssertionError出來。邏輯上等同於:
       if not condition:
               raise AssertionError()
    • 另外一種使用方法:assert condition,expression
      若是condition爲false,就raise一個描述爲 expression 的AssertionError出來。邏輯上等同於:
      if not condition:
                 raise AssertionError(expression)
      assert的異常參數,其實就是在斷言表達式後添加字符串信息,用來解釋斷言並更好的知道是哪裏出了問題。格式以下:
        assert expression [, arguments]
        assert 表達式 [, 參數]
  • 簡易的SSH
    • 客戶端
       1 import socket
       2 client = socket.socket()
       3 
       4
       5 client.connect(('localhost',9999))
       6 
       7 while True:
       8     cmd = input(">>:").strip()
       9     if len(cmd) == 0: continue
      10     client.send(cmd.encode("utf-8"))
      11     cmd_res_size = client.recv(1024) ##接受命令結果的長度
      12     print("命令結果大小:",cmd_res_size)
      client.send("準備好接收了,loser能夠發了".encode("utf-8"))
      13 received_size = 0 14 received_data = b'' 15 while received_size < int(cmd_res_size.decode()) : 16 data = client.recv(1024) 17 received_size += len(data) #每次收到的有可能小於1024,因此必須用len判斷 18 #print(data.decode()) 19 received_data += data 20 else: 21 print("cmd res receive done...",received_size) 22 print(received_data.decode()) 23 client.close()
    • 服務端
       1 import socket ,os,time
       2 server = socket.socket()
       3 server.bind(('localhost',9999) )
       4 
       5 server.listen()
       6 
       7 while True:
       8     conn, addr = server.accept()
       9     print("new conn:",addr)
      10     while True:
      11         print("等待新指令")
      12         data = conn.recv(1024)
      13         if not data:
      14             print("客戶端已斷開")
      15             break
      16         print("執行指令:",data)
      17         cmd_res = os.popen(data.decode()).read() #接受字符串,執行結果也是字符串
      18         print("before send",len(cmd_res))
      19         if len(cmd_res) ==0:
      20             cmd_res = "cmd has no output..."
      21 
      22         conn.send( str(len(cmd_res.encode())).encode("utf-8")    )     #先發大小給客戶端
      23         #time.sleep(0.5)
      client_ack=conn.recv(1024) #等待客戶端確認
      print("ack from client:",client_ack)
      24 conn.send(cmd_res.encode("utf-8")) 25 print("send done") 26 #os.path.isfile() 27 #os.stat("sock") 28 server.close()
  • FTP server
    • 讀取文件名
    • 檢測文件是否存在
    • 打開文件
    • 檢測文件大小
    • 發送文件大小給客戶端
    • 等待客戶端確認
    • 開始邊讀邊發數據
    • 發送MD5進行確認
       1 import hashlib
       2 import socket ,os,time
       3 server = socket.socket()
       4 server.bind(('0.0.0.0',9999) )
       5 server.listen()
       6 while True:
       7     conn, addr = server.accept()
       8     print("new conn:",addr)
       9     while True:
      10         print("等待新指令")
      11         data = conn.recv(1024)
      12         if not data:
      13             print("客戶端已斷開")
      14             break
      15         cmd,filename = data.decode().split()
      16         print(filename)
      17         if os.path.isfile(filename):
      18            f = open(filename,"rb")
      19            m = hashlib.md5()
      20            file_size = os.stat(filename).st_size
      21            conn.send( str(file_size).encode() ) #send file size
      22            conn.recv(1024) #wait for ack
      23            for line in f:
      24               m.update(line)
      25               conn.send(line)
      26            print("file md5", m.hexdigest())
      27            f.close()
      28            conn.send(m.hexdigest().encode()) #send md5
      29         print("send done")
      30 server.close()

       

  • FTP client
     1 import socket
     2 import hashlib
     3 client = socket.socket()
     4 client.connect(('localhost', 9999))
     5 while True:
     6     cmd = input(">>:").strip()
     7     if len(cmd) == 0: continue
     8     if cmd.startswith("get"):
     9         client.send(cmd.encode())
    10         server_response = client.recv(1024)
    11         print("servr response:", server_response)
    12         client.send(b"ready to recv file")
    13         file_total_size = int(server_response.decode())
    14         received_size = 0
    15         filename = cmd.split()[1]
    16         f = open(filename + ".new", "wb")
    17         m = hashlib.md5()
    18         while received_size < file_total_size:
    19             if file_total_size - received_size > 1024:  # 要收不止一次
    20                 size = 1024
    21             else:  # 最後一次了,剩多少收多少
    22                 size = file_total_size - received_size
    23                 print("last receive:", size)
    24             data = client.recv(size)
    25             received_size += len(data)
    26             m.update(data)
    27             f.write(data)
    28             # print(file_total_size,received_size)
    29         else:
    30             new_file_md5 = m.hexdigest()
    31             print("file recv done", received_size, file_total_size)
    32             f.close()
    33         server_file_md5 = client.recv(1024)
    34         print("server file md5:", server_file_md5)
    35         print("client file md5:", new_file_md5)
    36 client.close()

     

  • SocketServer #簡化網絡服務的開發
    詳情請見:https://www.cnblogs.com/Security-Darren/p/4594393.html
    • 主要類型
      該模塊有四個比較主要的類,其中經常使用的是 TCPServer 和 UDPServer。
      • TCPServer(socketserver.TCPServer
      • UDPServer(socketserver.UDPServer
      • UnixStreamServer(socketserver.UnixStreamServer),相似於TCPServer提供面向數據流的套接字鏈接,可是旨在UNIX平臺上可用
      • UnixDatagramServer(socketserver.UnixDatagramServer),相似於UDPServer提供面向數據報的套接字鏈接,可是旨在UNIX平臺上可用
        這四個類型同步地處理請求,也就是說一個請求沒有完成以前是不會處理下一個請求的,這種模式固然不適合生產環境,一個客戶端鏈接就可能拖延全部的執行。因此這個模塊還提供了兩種支持異步處理的類:
      • ForkingMixIn(socketserver.ForkingTCPServer 或者 socketserver.ForkingUDPServer),爲每個客戶端請求派生一個新的進程去專門處理(在Windows系統上沒法使用(緣由:調用fork),在Linux平臺上正常運行)
      • ThreadingMixIn(socketserver.ThreadingTCPServer 或者 socketserver.ThreadingUDPServer),爲每個客戶端請求派生一個新的線程去專門處理
        繼承自這兩個類型的服務端在處理新的客戶端鏈接時不會阻塞,而是建立新的進/線程專門處理客戶端的請求
    • 建立socketserver步驟:
      • 根據須要選擇一個合適的服務類型,如面向TCP鏈接的多進程服務器:ForkingTCPServer
      • 建立一個請求處理器(request handler)類型,這個類型的 handle()(相似於回調函數)方法中定義如何處理到達的客戶端鏈接
      • 實例化服務器,傳入服務器綁定的地址和第2步定義的請求處理器類
      • 調用服務器實例的handle_request()或serve_forever()方法,一次或屢次處理客戶請求

    • 客戶端
       1 import socket
       2 client = socket.socket()
       3 
       4 #client.connect(('192.168.16.200',9999))
       5 client.connect(('localhost',9999))
       6 
       7 while True:
       8     cmd = input(">>:").strip()
       9     if len(cmd) == 0: continue
      10     client.send(cmd.encode("utf-8"))
      11     cmd_res_size = client.recv(1024) ##接受命令結果的長度
      12     print("命令結果大小:",cmd_res_size)
      13     received_size = 0
      14     received_data = b''
      15     while received_size < int(cmd_res_size.decode()) :
      16         data = client.recv(1024)
      17         received_size += len(data) #每次收到的有可能小於1024,因此必須用len判斷
      18         #print(data.decode())
      19         received_data += data
      20     else:
      21         print("cmd res receive done...",received_size)
      22         print(received_data.decode())
      23 client.close()
    • 服務端
       1 import socketserver
       2 
       3 class MyTCPHandler(socketserver.BaseRequestHandler):
       4     def handle(self):
       5         while True:
       6             try:
       7                 self.data = self.request.recv(1024).strip()
       8                 print("{} wrote:".format(self.client_address[0]))
       9                 print(self.data)
      10                 self.request.send(self.data.upper())
      11             except ConnectionResetError as e:
      12                 print("err",e)
      13                 break
      14 if __name__ == "__main__":
      15     HOST, PORT = "localhost", 9999
      16     # Create the server, binding to localhost on port 9999
      17     server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
      18     server.serve_forever()
相關文章
相關標籤/搜索