2014-02-21 8 views
0

Я часто пишу простые TCP-серверы python, которые отвечают на запрос после разбора пакета с префиксом длины. Если предположить, что сокет был настроен, это обычно выглядит как это:Анализ пакетов из потока TCP

def tcp_server_loop(): 
    msg = '' 
    msg_len = 0 
    while True: 
     msg += sock.recv(4096) 
     if len(msg) >= 4 and msg_len == 0: 
      msg_len, = struct.unpack_from("!I", msg) 
     if len(msg) >= msg_len: 
      protocol.parse_packet(msg[:msg_len]) 
      msg = msg[msg_len:] 
      msg_len = 0 

Это работает и хорошо служил мне много раз, но я всегда был irk'ed строкой добавляющим в msg += sock.recv(4096). Для небольших пакетов это не так уж плохо, так как накладные расходы при распределении нового хранилища для этих небольших строк неплохие. Но для больших пакетов (МБ) много копий происходит за кулисами в строковой реализации Python.

В C или каком-либо подобном языке кольцевой буфер является очевидной структурой данных, размер которой соответствует наибольшему ожидаемому вами пакету. Но я не нашел аналогичную реализацию Python. Мне интересно, может ли кто-то улучшить мой код выше. Как вы реализуете эти типы серверов?

ответ

1

Быстрое предложение: вы можете переименовать packet_size в msg_len для наглядности. То, что вы пытаетесь проанализировать из потока TCP, - это сообщение протокола уровня приложения, а не сегмент TCP (так называемый TCP-пакет).

Но для решения вашего вопроса: более эффективным способом является получение вашего заголовка сообщения вторым фиксированным размером bytearray буфер длиной msg_len. Используйте это, чтобы сохранить данные, которые вы впоследствии читали.

+0

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

+0

Я не уверен, что понимаю, как создание bytearray повышает эффективность. Разве это не требовало бы копирования между 'msg' и массивом байтов? Текущая реализация передает только фрагмент в парсер протокола, который, как мне кажется, не требует копии. – user3339161

+0

Да, было бы, но я думаю, что точка доступа - это перераспределение памяти, когда вы добавляете к 'msg', а не к копии, если количество байтов вы' sock.recv() 'не велико. Если вы также создаете 'msg' в' bytearray', вы, вероятно, выиграете что-то еще, не требуя от интерпретатора преобразования типа. – cklin

Смежные вопросы