Чтение буфера сокета с использованием asyncore
Вопрос
Я новичок в Python (хотя я программирую на Java уже несколько лет), и я работаю над простым сетевым приложением на основе сокетов (просто для удовольствия). Идея состоит в том, что мой код подключается к удаленной конечной точке TCP, а затем прослушивает любые данные, передаваемые с сервера клиенту, и выполняет некоторый анализ этого.
Данные, загружаемые с сервера - > клиент - это кодированный в кодировке UTF-8 текст, и каждая строка отделяется CRLF
( \ x0D \ x0A
). Вы, наверное, догадались: идея в том, что клиент подключается к серверу (пока пользователь не отменит его), а затем читает и анализирует строки по мере их поступления.
Мне удалось заставить это работать, однако я не уверен, что делаю это совершенно правильно. Поэтому, следовательно, мои реальные вопросы (код для подражания):
<Ол> asyncore
? В настоящее время данные читаются и буферизуются следующим образом:
def handle_read(self):
self.ibuffer = b""
while True:
self.ibuffer += self.recv(self.buffer_size)
if ByteUtils.ends_with_crlf(self.ibuffer):
self.logger.debug("Got full line including CRLF")
break
else:
self.logger.debug("Buffer not full yet (%s)", self.ibuffer)
self.logger.debug("Filled up the buffer with line")
print(str(self.ibuffer, encoding="UTF-8"))
Функция ByteUtils.ends_with_crlf
просто проверяет последние два байта буфера на наличие \ x0D \ x0A
. Первый вопрос является основным (ответ основан на этом), но любые другие идеи / советы приветствуются. Спасибо.
Решение
TCP - это поток, и вам не гарантируется, что в вашем буфере не будет конца одного сообщения и начала следующего. Таким образом, проверка на наличие \ n \ r в конце буфера не будет работать должным образом во всех ситуациях. Вы должны проверить каждый байт в потоке.
И я настоятельно рекомендую вам использовать Twisted вместо asyncore. Примерно так (из памяти может не работать из коробки):
from twisted.internet import reactor, protocol
from twisted.protocols.basic import LineReceiver
class MyHandler(LineReceiver):
def lineReceived(self, line):
print "Got line:", line
f = protocol.ClientFactory()
f.protocol = MyHandler
reactor.connectTCP("127.0.0.1", 4711, f)
reactor.run()
Другие советы
Это еще проще - посмотрите asynchat и его set_terminator (и другие полезные лакомые кусочки в этом модуле). Twisted на несколько порядков богаче и мощнее, но, для достаточно простых задач, asyncore и asynchat (которые являются разработано так, чтобы беспрепятственно взаимодействовать), действительно очень просты в использовании, как вы начали наблюдать.