1. 程式人生 > 程式設計 >Python socket連線中的粘包、精確傳輸問題例項分析

Python socket連線中的粘包、精確傳輸問題例項分析

本文例項講述了Python socket連線中的粘包、精確傳輸問題。分享給大家供大家參考,具體如下:

粘包:

  • 發生原因:

當呼叫send的時候,資料並不是即時發給客戶端的。而是放到了系統的socket傳送緩衝區裡,等緩衝區滿了、或者資料等待超時了,資料才會傳送,所以有時候傳送太快的話,前一份資料還沒有傳給客戶端,那麼這份資料和上一份資料一起發給客戶端的時候就會造成“粘包” 。

  • 解決方案:

解決根源的思想是避免不同段的資料一起傳送。

    1. 方案1:前一段資料send完後,等待一段時間再send第二段資料。缺點:時間效率低,而且也無法完全避免問題【因為不清楚該設定多少時間才能保證前一份資料已經發送】
    2. 方案2:握手機制:前一段資料send完後,嘗試recv,等待客戶端迴應,確認第一段資料傳送完後,再send第二段資料。完美方案?

方案二的演示:

服務端【傳送方】程式碼:

import socket

server=socket.socket()
server.bind(("localhost",1234))
server.listen()

while True:
  print("正在等待。。。")
  conn,addr=server.accept()
  while True:
    try:
      conn.send(b"first info")
      ack=conn.recv(1024) #接收客戶端確認
      print(ack)
      conn.send(b"second info")
    except ConnectionResetError as e:
      print(e)
      break

server.close()

客戶端【接收方】程式碼:

import socket

client=socket.socket()

client.connect(("localhost",1234))

data=client.recv(1024)
print(data.decode())
client.send(b"ack")#傳送確認
data=client.recv(1024)
print(data.decode())
client.close()

不精確傳輸問題:

發生原因:

由於資料太大,傳送方一次send不完,而接收方只recv一次,使得影響了後面資料的傳輸

解決方案:

解決根源的思想是改變recv的次數。

  • 方案:將資料的大小發給接收方,讓接收方來決定recv的次數

方案實現程式碼【以解決長資料shell命令傳輸為例】:

服務端【傳送方】:

import socket,os

server=socket.socket()
server.bind(("localhost",1234))
server.listen()
while True:
  print("正在等待...")
  conn,addr=server.accept()
  print("連線成功!")
  while True:
    try:
      cmd=conn.recv(1024)
      data=os.popen(cmd.decode()).read()
      # print(data)
      cmd_len=len(data.encode())
      print(cmd_len)
      #發現這裡如果cmd_len為0會導致異常,有些是沒有返回值的command
      if cmd_len==0:
        data="command has nothing return"
        cmd_len=len(data.encode())
      ##因為這裡前面沒有傳送操作,所以不用擔心粘包,如果有則要考慮處理
      conn.send(str(cmd_len).encode())#因為len結果是int,所以還要轉換
      #這裡要處理粘包
      ack=conn.recv(1024)
      conn.send(data.encode())
    except ConnectionResetError as e:
      print(e)
      break

server.close()

客戶端【接收方】:

import socket

client=socket.socket()
client.connect(("localhost",1234))
while True:

  cmd = input(">>:")
  client.send(cmd.encode())
  data_len=client.recv(1024)
  data_len=int(data_len.decode())
  print(data_len)
  recv_len=0
  client.send(b'ack')
  total_data=b''
  while recv_len<data_len:
    data=client.recv(1024)
    recv_len+=len(data)
    total_data+=data
  print(total_data.decode())
client.close()
  • 利用這個原理可以實現檔案傳輸,只要能確定接受次數,就能保證檔案傳輸的大小正確。

更多關於Python相關內容可檢視本站專題:《Python Socket程式設計技巧總結》、《Python資料結構與演算法教程》、《Python函式使用技巧總結》、《Python字串操作技巧彙總》、《Python入門與進階經典教程》及《Python檔案與目錄操作技巧彙總》

希望本文所述對大家Python程式設計有所幫助。