программы зависают при взаимодействии с сокетом - PullRequest
2 голосов
/ 25 мая 2010

У меня есть две программы, 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()

Я уверен, что что-то здесь упускаю в тупике, но не знаю, что это такое.

Ответы [ 2 ]

3 голосов
/ 25 мая 2010

С блокирующими сокетами, которые используются по умолчанию, и я предполагаю, что вы используете (не уверен, так как вы используете загадочный модуль jmm_sockets), метод recv блокирует - он не возвращайте пустую строку, когда ей «больше нечего вернуть», как вы, похоже, предполагаете.

Вы можете обойти это, например, отправив явный символ-терминатор (который никогда не должен встречаться в имени файла), например, '\xff', после фактической строки, которую вы хотите отправить, и ожидания ее на другом конце в качестве указания на то, что вся строка уже получена.

1 голос
/ 25 мая 2010

TCP - это потоковый протокол. У него нет понятия границ сообщения. Для блокирующего сокета recv (n) вернет строку нулевой длины только тогда, когда отправитель закрыл сокет или явно вызвал shutdown (SHUT_WR). В противном случае он может вернуть строку длиной от одного до n байтов и будет блокировать, пока не будет хотя бы одного байта для возврата.

Вы должны разработать протокол, чтобы определить, когда у вас есть полное сообщение. Несколько способов:

  1. Использовать сообщение фиксированной длины.
  2. Отправка сообщения фиксированной длины с указанием общей длины сообщения, за которым следует переменная часть сообщения.
  3. Отправьте сообщение, за которым следует уникальное сообщение завершения, которое никогда не появится в сообщении.

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

...