Декодирование TCP-пакетов с использованием Python - PullRequest
1 голос
/ 02 февраля 2010

Я пытаюсь декодировать данные, полученные через TCP-соединение. Пакеты маленькие, не более 100 байт. Однако, когда их много, я получаю некоторые пакеты, соединенные вместе. Есть ли способ предотвратить это. Я использую Python

Я попытался разделить пакеты, мой источник ниже. Пакеты начинаются с байта STX и заканчиваются байтами ETX, байт, следующий за STX, является длиной пакета (недопустимые длины пакетов меньше 5), контрольная сумма - это последние байты перед ETX

def decode(data):
  while True:
    start = data.find(STX)
    if start == -1: #no stx in message
        pkt = ''
        data = ''
        break
    #stx found , next byte is the length
    pktlen = ord(data[1])
    #check message ends in ETX (pktken -1) or checksum invalid
    if pktlen < 5 or data[pktlen-1] != ETX or checksum_valid(data[start:pktlen]) == False:
        print "Invalid Pkt"
        data = data[start+1:]
        continue
    else:
        pkt = data[start:pktlen]
        data = data[pktlen:]
        break

return data , pkt

Я использую это так

#process reports
try:
    data = sock.recv(256) 
except: continue 
else:
    while data:
        data, pkt = decode(data) 
        if pkt:
           process(pkt)

Также, если в потоке данных несколько пакетов, лучше всего возвращать пакеты в виде коллекции списков или просто вернуть первый пакет

Я не очень знаком с python, только C, этот метод в порядке. Любой совет будет наиболее ценным. Заранее спасибо

Спасибо

Ответы [ 5 ]

5 голосов
/ 02 февраля 2010

Я бы создал класс, который отвечает за декодирование пакетов из потока, например:

class PacketDecoder(object):

    STX = ...
    ETX = ...

    def __init__(self):
        self._stream = ''

    def feed(self, buffer):
        self._stream += buffer

    def decode(self):
        '''
        Yields packets from the current stream.
        '''
        while len(self._stream) > 2:
            end = self._stream.find(self.ETX)
            if end == -1:
                break

            packet_len = ord(self._stream[1])
            packet = self._stream[:end]
            if packet_len >= 5 and check_sum_valid(packet):
                yield packet
            self._stream = self._stream[end+1:]

А потом используйте вот так:

decoder = PacketDecoder()
while True:
    data = sock.recv(256) 
    if not data:
        # handle lost connection... 
    decoder.feed(data)
    for packet in decoder.decode():
        process(packet)
4 голосов
/ 02 февраля 2010

TCP предоставляет поток данных, а не отдельные пакеты, на уровне интерфейса. Если вам нужны дискретные пакеты, вы можете использовать UDP (и обрабатывать потерянные или неупорядоченные пакеты самостоятельно) или поместить некоторые разделители данных в строку. Похоже, вы уже делаете это с STX / ETX в качестве разделителей. Однако, как вы заметили, вы получаете несколько сообщений в одном блоке данных из вашего стека TCP.

Обратите внимание, что если вы не выполняете какую-либо другую обработку, data в показанном вами коде не обязательно содержит целое число сообщений. То есть вполне вероятно, что последний STX не будет иметь соответствующий ETX. ETX будет в следующем data блоке без STX.

Возможно, вам следует прочитать отдельные сообщения из потока данных TCP и вернуть их по мере их появления.

3 голосов
/ 02 февраля 2010

Попробуйте scapy , мощную интерактивную программу для работы с пакетами.

0 голосов
/ 11 апреля 2010

Красиво и просто ... :) Хитрость в файле объекте.

f=sock.makefile()
while True:
  STX = f.read(1)
  pktlen = f.read(1)
  wholePacket = STX + pktlen + f.read(ord(pktlen)-2)
  doSomethingWithPacket(wholePacket)

И все! (Там тоже нетнужно проверять контрольные суммы при использовании TCP.)

А вот более «надежная» (?) версия (она использует STX и контрольную сумму):

f=sock.makefile()
while True:
  while f.read(1)!=STX:
    continue
  pktlen = f.read(1)
  wholePacket = STX + pktlen + f.read(ord(pktlen)-2)
  if checksum_valid(wholePacket):
    doSomethingWithPacket(wholePacket)
0 голосов
/ 02 февраля 2010

Откуда поступают данные? Вместо того, чтобы пытаться декодировать его вручную, почему бы не использовать превосходный пакет Impacket:

http://oss.coresecurity.com/projects/impacket.html

...