網絡編程基礎粘包現象

粘包

  • tcp是流式傳輸,字節流,數據與數據之間是沒有邊界的
    • 流式傳輸優勢:
      • 不限定長度
      • 可靠傳輸
    • 缺點:
      • 和一我的的通訊鏈接conn會一直佔用咱們的通訊資源
  • udp協議,面向數據包的傳輸
    • 數據包優勢
      • 因爲不須要創建鏈接,因此誰發的消息我都能接受到
    • 缺點
      • 不能傳輸過長的數據
      • 不可靠

粘包現象

  • 因爲流式傳輸的特色,產生了數據連續發送的粘包現象。
    • 在一個conn創建起來的鏈接上傳輸的多條數據是沒有邊界的
  • 數據的發送和接收實際上不是在執行send/recv的時候就馬上被髮送和接收,而是須要通過操做系統內核
  • Nagle 算法,可以將發送間隔實際很近的短數據合成一個包發送到接收端
  • 拆包機制: 當要發送的數據超過了網絡上可以傳輸的最大長度,就會被tcp協議強制拆包

解決粘包問題

  • struct模塊python

    • park("i",len(msg)) 把數字轉成4字節算法

    • unpack("i",bytes)[0] 把四字節轉換成長度網絡

    • server端
      import struct
      import socket
      
      sk = socket.socket()
      sk.bind(('127.0.0.1',9090))
      sk.listen()
      
      conn,addr = sk.accept()
      while True:
          s = input('>>>').encode('utf-8')
          pack_num = struct.pack('i',len(s))
          conn.send(pack_num)
          conn.send(s)
      conn.close()
      sk.close()
    • client端
      import socket
      import struct
      sk = socket.socket()
      sk.connect(('127.0.0.1',9090))
      
      while True:
          pack_num = sk.recv(4)
          num = struct.unpack('i',pack_num)[0]
          ret = sk.recv(num)
          print(ret.decode('utf-8'))
      sk.close()

併發的 socketserver

  • 實現同一時刻server端能夠和多個client端創建鏈接

驗證客戶端連接的合法性

  • server端併發

  • import os
    import hmac
    import socket
    def auth(conn):
        msg = os.urandom(32)  # # 生成一個隨機的字符串
        conn.send(msg)  # # 發送到client端
        result = hmac.new(secret_key, msg)  # 處理這個隨機字符串,獲得一個結果
        client_digest = conn.recv(1024)  # 接收client端處理的結果
        if result.hexdigest() == client_digest.decode('utf-8'):
            print('是合法的鏈接')  # 對比成功能夠繼續通訊
            return True
        else:
            print('不合法的鏈接')  # 不成功 close
            return False
    secret_key = b'alex_sb'
    sk = socket.socket()
    sk.bind(('127.0.0.1',9000))
    sk.listen()
    conn,addr = sk.accept()
    if auth(conn):
        print(conn.recv(1024))
        # 正常的和client端進行溝通了
        conn.close()
    else:
        conn.close()
    sk.close()
  • client端dom

  • import hmac
    import socket
    def auth(sk):
        msg = sk.recv(32)
        result = hmac.new(key, msg)
        res = result.hexdigest()
        sk.send(res.encode('utf-8'))
    
    key = b'alex_s'
    sk = socket.socket()
    sk.connect(('127.0.0.1',9000))
    auth(sk)
    sk.send(b'upload')
    # 進行其餘正常的和server端的溝通
    sk.close()
相關文章
相關標籤/搜索