2010-02-02 94 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