Программы висит во время взаимодействия сокета
-
04-10-2019 - |
Вопрос
У меня есть две программы, sendfile.py и recvfile.py, которые должны взаимодействовать, чтобы отправить файл через сеть. Они общаются над розетками TCP. Общение предполагается идти что-то вроде этого:
sender =====filename=====> receiver
sender <===== 'ok' ======= receiver
or
sender <===== 'no' ======= receiver
if ok:
sender ====== file ======> receiver
у меня есть
Код отправителя и приемника здесь:
Отправитель:
import sys
from jmm_sockets import *
if len(sys.argv) != 4:
print "Usage:", sys.argv[0], "<host> <port> <filename>"
sys.exit(1)
s = getClientSocket(sys.argv[1], int(sys.argv[2]))
try:
f = open(sys.argv[3])
except IOError, msg:
print "couldn't open file"
sys.exit(1)
# send filename
s.send(sys.argv[3])
# receive 'ok'
buffer = None
response = str()
while 1:
buffer = s.recv(1)
if buffer == '':
break
else:
response = response + buffer
if response == 'ok':
print 'receiver acknowledged receipt of filename'
# send file
s.send(f.read())
elif response == 'no':
print "receiver doesn't want the file"
# cleanup
f.close()
s.close()
Получатель:
from jmm_sockets import *
s = getServerSocket(None, 16001)
conn, addr = s.accept()
buffer = None
filename = str()
# receive filename
while 1:
buffer = conn.recv(1)
if buffer == '':
break
else:
filename = filename + buffer
print "sender wants to send", filename, "is that ok?"
user_choice = raw_input("ok/no: ")
if user_choice == 'ok':
# send ok
conn.send('ok')
#receive file
data = str()
while 1:
buffer = conn.recv(1)
if buffer=='':
break
else:
data = data + buffer
print data
else:
conn.send('no')
conn.close()
Я уверен, что я что-то упускаю здесь, в видах тупика, но не знаю, что это такое.
Решение
TCP - это протокол потоковой передачи. Он не имеет концепции границ сообщений. Для блокирующего розетки, recv.(n) вернет строку нулевой длины только тогда, когда отправитель закрыл розетку или явно называемую неисправность(Shut_wr). В противном случае он может вернуть строку с одного до N BYTES по длине и заблокирует, пока у нее не будет, по крайней мере, один байт, чтобы вернуться.
Вам решать разработать протокол, чтобы определить, когда у вас есть полное сообщение. Несколько способов:
- Используйте сообщение фиксированной длины.
- Отправьте сообщение фиксированной длины, указывающее на полную длину сообщения, а затем переменная часть сообщения.
- Отправьте сообщение, а затем уникальное сообщение о прекращении, которое никогда не возникнет в сообщении.
Другой вопрос, который вы можете столкнуться, это то, что Отправить() не гарантируется отправлять все данные. Возвращаемое значение указывает на то, насколько фактически отправлены байты, и это ответственность отправителя, чтобы продолжать звонить отправить с оставшимся байтами сообщений, пока они не будут отправлены. Вы предпочитаете использовать отправьте все() Метод.
Другие советы
С блокирующими розетками, которые имеют значение по умолчанию, и я предполагаю, что вы используете (не можете быть уверены, так как вы используете загадочный модуль jmm_sockets
), то recv
Метод блокирует - он не будет возвращать пустую строку, когда она имеет «ничего больше, чтобы вернуться на данный момент», как вы, кажется, предполагаете.
Вы можете работать вокруг этого, например, путем отправки явного символа терминатора (который никогда не должен происходить в именем файле), например '\xff'
, После фактической строки вы хотите отправить и ждать его на другом конце в качестве указания, что вся строка теперь была получена.