我創建了 server.py 和 client.py,目的是在兩者之間發送文本和二進制檔案。我的代碼適用于小型文本和小型二進制檔案,但是大型二進制檔案不起作用。
在我的測驗中,我使用了一個 1.5 KB 的 .ZIP 檔案,我可以毫無問題地發送它。但是,當我嘗試發送 44 MB .ZIP 檔案時,我遇到了問題。
我的客戶端代碼作業如下:
- 客戶端創建一個字典,其中包含有關要發送的檔案的元資料。
- 二進制檔案是 base64 編碼的,并作為一個值添加到字典的“filecontent”鍵中。
- 字典是 JSON 序列化的。
- 序列化字典的長度是計算出來的,并在序列化字典前加上固定長度的前綴。
- 客戶端將整個訊息發送到服務器。
在服務器上:
- 服務器接收固定長度的報頭并解釋傳輸中訊息的大小。
- 服務器以 MAXSIZE 塊(測驗設定為 500)讀取訊息,臨時存盤它們。
- 一旦接收到整個訊息,服務器就會加入整個訊息。
- 服務器 base64 解碼屬于“filecontent”鍵的值。
- 接下來,它將檔案的內容寫入磁盤。
正如我所說,這適用于我的 1.5 KB .ZIP 檔案,但對于 44 MB .ZIP 檔案,它會在服務器上的第 3 步中中斷。錯誤由 json.decoder 引發。它抱怨“未終止的字串開始于...”
在進行故障排除時,我發現訊息的最后一部分沒有到達。這解釋了來自 json.decoder 的投訴。我還發現客戶端發送61841613作為定長頭,應該是62279500,相差437887。
當我不讓客戶端計算訊息的大小,而只是將大小硬編碼為 62279500 時,一切都會按預期作業。這讓我相信客戶端計算較大檔案的訊息大小的方式有問題。但是我無法弄清楚出了什么問題。
以下是代碼的相關部分:
# client.py
connected = True
while connected:
# Actual dictionary contains more metadata
msg = { "filename" : "test.zip" , "author" : "marc" , "filecontent" : "" }
myfile = open("test.zip", "rb")
encoded = base64.b64encode(myfile.read())
msg["filecontent"] = encoded.decode("ascii")
msg = json.dumps(msg)
header = "{:<10}".format(len(msg))
header_msg = header msg
client.sendall(header_msg.encode("utf-8"))
# server.py
HEADER = 10
MAXSIZE = 500
connected = True
while connected:
msg = conn.recv(HEADER).decode("utf-8")
SIZE = int(msg)
totalmsg = []
while SIZE > 0:
if SIZE > MAXSIZE:
msg = conn.recv(MAXSIZE).decode("utf-8")
totalmsg.append(msg)
SIZE = SIZE - MAXSIZE
else:
msg = conn.recv(SIZE).decode("utf-8")
totalmsg.append(msg)
SIZE = 0
msg = json.loads("".join(totalmsg))
decoded = base64.b64decode(msg["filecontent"])
myfile = open(msg["filename"], "wb")
myfile.write(decoded)
myfile.close()
uj5u.com熱心網友回復:
如評論中所述,最多conn.recv(MAXSIZE)接收MAXSIZE 但可以回傳更少。該代碼假定它始終收到請求的金額。也沒有理由對檔案資料進行 base64 編碼;它只是使檔案資料更大。套接字是一個位元組流,所以只需發送位元組。
標題可以通過它和資料之間的標記來描述。下面我使用了 CRLF 并將標頭撰寫為單個 JSON 行,還演示了在同一連接上發送幾個檔案:
客戶端.py
import socket
import json
def transmit(sock, filename, author, content):
msg = {'filename': filename, 'author': author, 'length': len(content)}
data = json.dumps(msg, ensure_ascii=False).encode() b'\r\n' content
sock.sendall(data)
client = socket.socket()
client.connect(('localhost',5000))
with client:
with open('test.zip','rb') as f:
content = f.read()
transmit(client, 'test.zip', 'marc', content)
content = b'The quick brown fox jumped over the lazy dog.'
transmit(client, 'mini.txt', 'Mark', content)
服務器.py
import socket
import json
import os
os.makedirs('Downloads', exist_ok=True)
s = socket.socket()
s.bind(('',5000))
s.listen()
while True:
c, a = s.accept()
print('connected:', a)
r = c.makefile('rb') # wrap socket in a file-like object
with c, r:
while True:
header_line = r.readline() # read in a full line of data
if not header_line: break
header = json.loads(header_line) # process the header
print(header)
remaining = header['length']
with open(os.path.join('Downloads',header['filename']), 'wb') as f:
while remaining :
# Unlike socket.recv() the makefile object won't return less
# than requested unless the socket is closed.
count = f.write(r.read(min(10240, remaining)))
if not count: # socket closed?
if remaining:
print('Unsuccessful')
break
remaining -= count
else:
print('Success')
print('disconnected:', a)
輸出:
connected: ('127.0.0.1', 14117)
{'filename': 'test.zip', 'author': 'marc', 'length': 52474063}
Success
{'filename': 'mini.txt', 'author': 'Mark', 'length': 45}
Success
disconnected: ('127.0.0.1', 14117)
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/462591.html
