Отправка файла через TCP-сокеты в Python
Я успешно смог скопировать содержимое файла (изображение) в новый файл. Однако, когда я пытаюсь сделать то же самое по TCP-сокетам, я сталкиваюсь с проблемами. Цикл сервера не завершается. Клиентский цикл выходит, когда он достигает EOF, однако сервер не может распознать EOF.
Здесь код:
Сервер
import socket # Import socket module
s = socket.socket() # Create a socket object
host = socket.gethostname() # Get local machine name
port = 12345 # Reserve a port for your service.
s.bind((host, port)) # Bind to the port
f = open('torecv.png','wb')
s.listen(5) # Now wait for client connection.
while True:
c, addr = s.accept() # Establish connection with client.
print 'Got connection from', addr
print "Receiving..."
l = c.recv(1024)
while (l):
print "Receiving..."
f.write(l)
l = c.recv(1024)
f.close()
print "Done Receiving"
c.send('Thank you for connecting')
c.close() # Close the connection
Client
import socket # Import socket module
s = socket.socket() # Create a socket object
host = socket.gethostname() # Get local machine name
port = 12345 # Reserve a port for your service.
s.connect((host, port))
s.send("Hello server!")
f = open('tosend.png','rb')
print 'Sending...'
l = f.read(1024)
while (l):
print 'Sending...'
s.send(l)
l = f.read(1024)
f.close()
print "Done Sending"
print s.recv(1024)
s.close # Close the socket when done
Вот скриншот:
Сервер
![Server]()
Client
![Client]()
Изменить 1: дополнительные данные скопированы. Сделать файл "не полным".
В первом столбце показано изображение, которое было получено. Кажется, он больше, чем тот, который был отправлен. Из-за этого я не могу открыть изображение. Это похоже на поврежденный файл.
![File sizes]()
Изменить 2: Вот как я это делаю в консоли. Размеры файлов здесь одинаковы.
![Python Console]()
![Same file sizes]()
Ответы
Ответ 1
Клиент должен уведомить, что он завершил отправку, используя socket.shutdown
(не socket.close
, которые закрывают часть чтения и записи сокета):
...
print "Done Sending"
s.shutdown(socket.SHUT_WR)
print s.recv(1024)
s.close()
UPDATE
Клиент отправляет Hello server!
на сервер; который записывается в файл на стороне сервера.
s.send("Hello server!")
Удалите строку выше, чтобы избежать ее.
Ответ 2
Снимите код ниже
s.send("Hello server!")
потому что вы отправляете s.send("Hello server!")
на сервер, поэтому ваш выходной файл несколько больше по размеру.
Ответ 3
Проблема заключается в дополнительном 13 байт, который server.py получает в начале. Чтобы разрешить это, напишите "l = c.recv(1024)" дважды перед циклом while, как показано ниже.
print "Receiving..."
l = c.recv(1024) #this receives 13 bytes which is corrupting the data
l = c.recv(1024) # Now actual data starts receiving
while (l):
Это устраняет проблему, пробовали с разными форматами и размерами файлов. Если кто-то знает, к чему относится этот начальный 13 байт, ответьте.
Ответ 4
Поместите файл внутри while True
так
while True:
f = open('torecv.png','wb')
c, addr = s.accept() # Establish connection with client.
print 'Got connection from', addr
print "Receiving..."
l = c.recv(1024)
while (l):
print "Receiving..."
f.write(l)
l = c.recv(1024)
f.close()
print "Done Receiving"
c.send('Thank you for connecting')
c.close()
Ответ 5
вы можете изменить условие цикла в соответствии со следующим кодом, когда длина l меньше размера буфера, это означает, что он достиг конца файла
while (True):
print "Receiving..."
l = c.recv(1024)
f.write(l)
if len(l) < 1024:
break
Ответ 6
Вы можете отправить какой-нибудь флаг, чтобы остановить цикл на сервере
например
сервер:
import socket
s = socket.socket()
s.bind(("localhost", 5000))
s.listen(1)
c,a = s.accept()
filetodown = open("img.png", "wb")
while True:
print("Receiving....")
data = c.recv(1024)
if data == b"DONE":
print("Done Receiving.")
break
filetodown.write(data)
filetodown.close()
c.send("Thank you for connecting.")
c.shutdown(2)
c.close()
s.close()
#Done :)
clinet:
import socket
s = socket.socket()
s.connect(("localhost", 5000))
filetosend = open("img.png", "rb")
data = filetosend.read(1024)
while data:
print("Sending...")
s.send(data)
data = filetosend.read(1024)
filetosend.close()
s.send(b"DONE")
print("Done Sending.")
print(s.recv(1024))
s.shutdown(2)
s.close()
#Done :)