Передача файлов с использованием потока сокетов выполняется слишком медленно. Почти 100кбит/с. Я использовал модуль сокета Python, чтобы сделать этот код. Он отправляет данные клиенту, когда клиент отправляет имя файла. Как я могу увеличить скорость этой штуки?
Ниже код сервера
import socket
import os
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('localhost', 9999))
server.listen()
client, addr = server.accept()
msg = client.recv(1024).decode()
file = open("Server_files/"+msg, "rb")
file_size = os.path.getsize("Server_files/"+msg)
# client.send("Received_image.png".encode())
client.send(str(file_size).encode())
data = file.read()
client.sendall(data)
client.send(b"<END>")
file.close()
client.close()
Ниже приведен код клиента
import tqdm
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('localhost', 9999))
file_name = input("Enter the file name: ")
client.send(file_name.encode())
file_size = client.recv(1024).decode()
print(file_size)
file = open(file_name, "wb")
file_bytes = b""
done = False
progress = tqdm.tqdm(unit = "B", unit_scale=True, unit_divisor=1000,
total=int(file_size))
while not done:
data = client.recv(1024)
if file_bytes[-5:] == b"<END>":
done = True
else:
file_bytes += data
progress.update(1024)
file.write(file_bytes)
file.close()
client.close()






Вместо того, чтобы постоянно добавлять входящие данные в file_bytes (что потенциально требует много оперативной памяти, а также требует, чтобы Python несколько раз перераспределял буфер большего размера), вы должны просто записывать входящие data непосредственно в file по мере их получения.
Также может помочь увеличить размер чанка с 1024 до чего-то большего, может быть 128*1024; это позволило бы системным вызовам выполнять больше работы при каждом вызове.
Вот полное решение (Python 3.10), которое позволяет быстро загружать несколько файлов. Он использует socket.makefile для буферизации данных, with для автоматического закрытия сокетов, файлов и сброса tqdm прогресса, а также записывает данные как полученные для скорости.
Обратите внимание, что TCP не является протоколом обмена сообщениями. Он отправляет байты и получает байты в том же порядке, но не обязательно с одинаковыми «разрывами». Таким образом, send('filename') и send('filesize') могут быть recv(1024) как 'filenamefilesize' или 'filenamefi' и 'lesize' или любым другим разрывом. Итак, определите протокол:
Сервер:
Клиент:
сервер.py
import socket
import os
BLOCK = 128 << 10 # 128KB
with socket.socket() as server:
server.bind(('', 9999))
server.listen()
while True:
client, addr = server.accept()
try:
with (client,
client.makefile('rb') as rfile,
client.makefile('wb') as wfile):
while True:
filename = rfile.readline()
if not filename: break
fullname = os.path.join('Server_files', filename.decode().rstrip('\n'))
file_size = os.path.getsize(fullname)
wfile.write(f'{file_size}\n'.encode())
print(f'Sending {fullname}...')
with open(fullname, 'rb') as file:
while data := file.read(BLOCK):
wfile.write(data)
wfile.flush() # make sure anything remaining in makefile buffer is sent.
print(f' Complete ({file_size} bytes).')
except ConnectionResetError:
print('Client aborted.')
клиент.py
import socket
import tqdm
BLOCK = 1 << 20 # 1MB
with socket.socket() as client:
client.connect(('localhost', 9999))
with (client.makefile('rb') as rfile,
client.makefile('wb') as wfile):
while True:
file_name = input('File name (just ENTER to quit): ')
if not file_name: break
wfile.write(f'{file_name}\n'.encode())
wfile.flush() # make sure makefile buffer is fully sent
file_size = int(rfile.readline().decode())
with (tqdm.tqdm(unit='B',
unit_scale=True,
unit_divisor=1000,
total=file_size) as progress,
open(file_name, 'wb') as file):
remaining = file_size
while remaining:
data = rfile.read(BLOCK if remaining > BLOCK else remaining)
file.write(data)
progress.update(len(data))
remaining -= len(data)
Пример вывода (обратите внимание на скорость загрузки):
File name (just ENTER to quit): bigfile1
100%|██████████████████████████████████████████████████████████| 191M/191M [00:00<00:00, 706MB/s]
File name (just ENTER to quit): bigfile2
100%|██████████████████████████████████████████████████████████| 218M/218M [00:00<00:00, 718MB/s]
File name (just ENTER to quit):
Обратите внимание, что TCP не является протоколом сообщений. 1 отправка не всегда равна 1 получению того же размера, поэтому отправьте имя файла и размер файла с разделителем, например новой строкой, и буферизируйте получение, пока у вас не будет полной строки.