Подтвердить что ты не робот

Разъем Python отправляет EOF

У меня есть простая программа сокетов для передачи файлов, где один сокет отправляет данные файла, а другой сокет получает данные и записывает их в файл

Мне нужно отправить подтверждение , как только передача будет завершена от адресата до источника

Код для пункта назначения

s.accept()
f = s.makefile()
f.read(1024)

Код для источника

s.connect(('localhost',6090))
f = s.makefile()
f.write('abcd') 
f.flush()

Здесь возникает проблема, так как "abcd" не 1024 байта, назначение будет блокироваться до получения 1024 байтов
Решение было бы закрыть() сокет, но так как мне нужно подтверждение от адресата, я не могу закрыть сокет.
Как сообщить целевому пункту прекратить блокировку? Я подумывал написать символ EOF Я читал онлайн, что "\ x04" - это EOF, но он не работает.
Также, поскольку данные могут быть двоичными, я не хочу использовать метод readline().

4b9b3361

Ответ 1

Создайте протокол (соглашение между клиентом и сервером) о том, как отправлять сообщения. Один простой способ - "первый байт - это длина сообщения, за которым следует сообщение". Пример:

Client

Python 2.6.5 (r265:79096, Mar 19 2010, 21:48:26) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from socket import *
>>> s=socket()
>>> s.connect(('localhost',5000))
>>> f=s.makefile()
>>> f.write('\x04abcd')
>>> f.flush()

Сервер

Python 2.6.5 (r265:79096, Mar 19 2010, 21:48:26) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from socket import *
>>> s=socket()
>>> s.bind(('localhost',5000))
>>> s.listen(1)
>>> c,a=s.accept()
>>> f=c.makefile()
>>> length=ord(f.read(1))
>>> f.read(length)
'abcd'

Ответ 2

Запись и чтение из сокета являются отдельными. Вы можете попытаться закрыть сокет для записи и оставить его открытым для чтения.

См. http://docs.python.org/library/socket.html#socket.socket.shutdown

Кроме того, что делает FTP, используется два сокета: один для данных и один для этого "подтверждения".

Вы бы более счастливы, используя второй сокет для этих дополнительных метаданных.

Ответ 3

Фактически вы не хотите использовать маркер "EOF", если вы собираетесь отправлять любые двоичные данные через трубу. Что произойдет, если ваши двоичные данные включают в себя эту последовательность байтов? Вы можете "убежать" от него, чтобы это не происходило, но это требует от вас проверки на обоих концах, а затем убедитесь, что вы также избегаете escape-последовательности.

Если вы делаете это для какой-то производственной системы, посмотрите, есть ли сетевой API, который вы можете использовать (что-то вроде FTP, HTTP, SFTP и т.д.).

Если это школьный или маломасштабный проект, вам нужно написать протокол связи. Простейшим может быть отправитель для трансляции одного двоичного целого X (выбрать размер данных и придерживаться его), а затем отправить X байты двоичных данных. Получатель сначала мешает размеру, а только рассчитывает получить этот объем данных. Помните, что если вам нужно отправить больше байтов, чем может отправить размер данных X, вам нужно "обрезать" ваши данные.

Также подумайте, что происходит, когда связь потеряна в середине передачи. Вы можете установить таймауты в read(), но тогда вам нужно восстановить изящно, если связь возобновится сразу после вашего таймаута (хотя нежелание всех данных считать изящным в зависимости от системы).