Почему я получаю строку из сокета до escape-последовательности \ n новой строки в python? - PullRequest
6 голосов
/ 05 декабря 2011

Предполагается получить из сокета tcp строку из 2 строк, но на самом деле я получаю только строку до новой строки.

     socket = socket(AF_INET,SOCK_STREAM)
     socket.connect((ip,port))
     data = socket.recv(1024)
     print "%s" % data

если сейчас вызывать функцию приема, она получит вторую часть строки после строки разрыва. Это не то, что я хочу на самом деле. Он должен вернуть всю строку из первого вызова. Когда я использую nc для подключения к серверу, я обычно получаю строку в начале соединения. Почему это происходит?

1 Ответ

7 голосов
/ 05 декабря 2011

Поскольку TCP является протоколом потокового (как указано SOCK_STREAM), нет фиксированных границ сообщений или пакетов, и вы никогда не сможете быть уверены, что получите все одним вызовом recv,Вам просто нужно вызвать recv в цикле, добавить в буфер и выйти из цикла, когда вы сочтете, что у вас достаточно.Большинство текстовых протоколов используют либо перевод строки, чтобы сообщить, что чтение выполнено, и что-то сделать с полученными данными.Другие протоколы используют другие символы или последовательности байтов.

В вашем случае, если нет специального символа, говорящего о достижении конца текущих данных, у вас есть два решения:

  1. Использовать тайм-аут: если новые данные не были получены в течение некоторого времени, распечатайте их.

  2. Неблокирующие сокеты: просто читайте в цикле, добавляя данные ввнутренний буфер.Когда вызов recv выдает ошибку с errno, равным errno.EWOULDBLOCK, тогда больше нет необходимости читать и распечатывать полученные данные.

Альтернатива 2,вместе с пакетом select, вероятно, лучший путь.

Edit

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

# Need to import: package socket, package select, package errno

# Create socket and connect to server

# Make the socket non-blocking (see http://docs.python.org/library/socket.html#socket.socket.setblocking)
socket.setblocking(0)

run_main_loop = True
while run_main_loop:
    # Wait for events...
    read_ready, _, _ = select.select([socket], None, None)

    if socket in read_ready:
        # The socket have data ready to be received
        buffer = ''
        continue_recv = True

        while continue_recv:
            try:
                # Try to receive som data
                buffer += socket.recv(1024)
            except socket.error, e:
                if e.errno != errno.EWOULDBLOCK:
                    # Error! Print it and tell main loop to stop
                    print 'Error: %r' % e
                    run_main_loop = False
                # If e.errno is errno.EWOULDBLOCK, then no more data
                continue_recv = False

    # We now have all data we can in "buffer"
    print '%r' % buffer

socket.close()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...