2010-02-02 194 views
1

我试图解码通过tcp连接接收到的数据。数据包很小,不超过100字节。然而,当他们中的很多人收到一些连在一起的数据包时。有没有办法来防止这一点。我正在使用python使用python解码tcp数据包

我试图分开数据包,我的源代码如下。分组开始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

我将创建一个类,负责数据包从一个数据流进行解码,这样的:

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) 
+0

感谢布鲁诺,我没有完全理解它,因为我是新来的python和不熟悉发电机。然而,这是一个优雅的解决方案 – mikip 2010-02-02 16:24:52

4

TCP提供的数据流,而不是单个的数据包,在接口级。如果你想要独立的数据包,你可以使用UDP(并且自己处理丢失或乱序的数据包),或者将一些数据分隔符内联。听起来你已经这么做了,用STX/ETX作为你的分隔符。但是,正如您注意到的那样,您可以从TCP堆栈的一个数据块中获得多条消息。

请注意,除非您正在做其他一些处理,否则您显示的代码中的data不一定包含整数个消息。也就是说,最后一个STX很可能没有匹配的ETX。 ETX将在下一个没有STX的data块中。

您应该从TCP数据流中读取单个消息,并在发生时将其返回。

+0

感谢mpez0,你能否详细说明你回复的最后一行。你的意思是,如果我有说三个分组数据,我应该返回 (1)第一包中发现和 (2)中的数据 - 第一包 然后再次调用子程序,直到没有包其余 在数据中。 谢谢 – mikip 2010-02-02 13:47:17

+0

是的。在一个例程中将来自TCP的读取和来自数据流的初始分析组合在一起,该例程可以处理TCP读取之间的消息拆分。调用该例程以获取下一条消息(或者,如果您愿意,可以使用可用消息列表)或返回标志以获取无消息。 不知道这是最好的还是典型的Python成语,但它会起作用。 – mpez0 2010-02-03 13:56:43

0

数据从哪里来?不要试图用手将其解码,为什么不使用优秀Impacket包:

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

+0

我想为此使用Python,我需要随后处理数据 – mikip 2010-02-02 14:19:36

+0

@mikip,请访问链接... impacket是一个Python解决方案。由于某种原因你的意思是“纯Python”吗?更好地解释为什么然后... – 2010-02-02 14:31:01

+0

无论如何,Impacket *是*纯Python。它是使用C扩展的pcapy,但是这里mikip似乎已经完成了捕获部分。 – fraca7 2010-02-02 15:30:40

3

尝试scapy,一个强大的交互式数据包处理程序。

+0

想为此使用Python,我需要随后处理数据 – mikip 2010-02-02 14:26:50

+3

@mikip,那么您认为“scapy”中的“py”代表什么? ;-) – 2010-02-02 14:30:09

0

尼斯和简单... :) 诀窍在于file对象。

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

请注意,f.read(1)将阻塞,直到接收到字节或套接字的另一端**关闭。这可能会让你陷入麻烦,因为你无法关闭客户端的套接字。查看[this SO question](http://stackoverflow.com/q/6795500/157744)了解详细示例。哦,我希望这会工作。 – 2013-04-21 16:27:00