Python Передача файлов через socket

Пытаюсь сделать передачу файла через socket. Сам код работает и файлы передаются, НО когда я пытаюсь передать крупный файл (например картинку), данные отдаются один раз и потом все завершается. В итоге та же картинка просто обрывается сверху, так как данные не передались до конца. Как можно это решить? Я понимаю, что нужен цикл, но как его добавить - вообще не понимаю

Код сервера

import socket
s = socket.socket()
host = socket.gethostname()
port = 8080
s.bind((host, port))
s.listen(1)
print(host)
print("waiting...")
conn, addr = s.accept()
print(addr, "connected")
filename = input("enter filename: ")
file = open(filename, "rb")
file_data = file.read(4096)
conn.send(file_data)
print("file sended")

Код клиента:

import socket
s = socket.socket()
host = input("enter host address of sender: ")
port = 8080
s.connect((host, port))
print("connected")
filename = input("enter incoming filename: ")
file = open(filename, "wb")
file_data = s.recv(4096)
file.write(file_data)
file.close()
print("file downloaded")

Ответы (1 шт):

Автор решения: eri

Файл передается кусочками в цикле, Вы передали только один кусочек. Для более взрослого кода на юниксоидах используйте sendfile - производительность больше в разы, а этот код исправляется так:

Код сервера

import socket
s = socket.socket()
host = socket.gethostname()
port = 8080
s.bind((host, port))
s.listen(1)
print(host)
print("waiting...")
conn, addr = s.accept()
print(addr, "connected")
filename = input("enter filename: ")
file = open(filename, "rb")
while True:
    file_data = file.read(4096)
    conn.send(file_data)
    if not file_data:
        break
conn.close()
print("file sended")

Код клиента:

import socket
s = socket.socket()
host = input("enter host address of sender: ")
port = 8080
s.connect((host, port))
print("connected")
filename = input("enter incoming filename: ")
file = open(filename, "wb")
while True:
    file_data = s.recv(4096)
    file.write(file_data)
    if not file_data:
        break
file.close()
print("file downloaded")

П.С. короткая запись

while file.write(s.recv(4096)): pass

sendfile на сервере, в виндовс выполнится через цикл с send, на юниксах через sendfile

conn.sendfile(file)

на клиенте нет функции на высоком уровне, оставь пока recv, но можно размер буфера побольше поставить. Разберусь с offset на низком уровне - допишу пример.

→ Ссылка