2016-01-21 113 views
2

因此,我對網絡非常陌生,我使用Python Socket庫連接到傳輸位置數據流的服務器。Python套接字接收到來自服務器的不一致消息

這裏是使用的代碼。

import socket 

BUFFER_SIZE = 1024 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.connect((gump.gatech.edu, 756)) 

try: 
    while (1): 
     data = s.recv(BUFFER_SIZE).decode('utf-8') 
     print(data) 
except KeyboardInterrupt: 
    s.close() 

問題是數據以不一致的形式到達。

大多數它到達正確的形式是這樣的時代:

2016-01-21 22:40:07,441,-84.404153,33.778685,5,3 

但其他時候可以到貨分成兩行,像這樣:

2016-01-21 

22:40:07,404,-84.396004,33.778085,0,0 

有趣的是,當我使用Putty建立到服務器的原始連接時,我只能得到正確的表單而不能拆分。所以我想象一下,發生了一些分裂信息的事情。或者是Putty正在做的事情,以便始終正確地組裝它。

我需要的是變量data始終包含適當的行。任何想法如何做到這一點?

+1

它發生在TCP和套接字。理論上它可以一次達到一個字節。你的代碼需要重新拼接起來。至於如何實現這一點,你可能會在你的數據包中加入一個頭文件。如果您將前兩個或四個字節作爲數據的長度,則重新組裝應該很簡單。 –

+1

請參閱此處的答案,瞭解爲什麼會發生這種更詳細的描述:http://stackoverflow.com/a/1716173/2372812 –

回答

1

最好是認爲插座作爲數據的連續流,可以在點點滴滴,或洪水到達。

特別是,接收器的工作是將數據分解成它應該包含的「記錄」,套接字不會奇蹟般地知道如何爲你做這件事。這裏的記錄是行,所以你必須讀取數據並自行分割。

你不能保證一個單一的完整行recv。它可能是:

  • 只是一行的一部分;
  • 或幾行;
  • 或者最有可能的是多行和另一行。

試着這麼做:(未經測試)

# we'll use this to collate partial data 
data = "" 

while 1: 
    # receive the next batch of data 
    data += s.recv(BUFFER_SIZE).decode('utf-8') 

    # split the data into lines 
    lines = data.splitlines(keepends=True) 

    # the last of these may be a part line 
    full_lines, last_line = lines[:-1], lines[-1] 

    # print (or do something else!) with the full lines 
    for l in full_lines: 
     print(l, end="") 

    # was the last line received a full line, or just half a line? 
    if last_line.endswith("\n"): 
     # print it (or do something else!) 
     print(last_line, end="") 

     # and reset our partial data to nothing 
     data = "" 
    else: 
     # reset our partial data to this part line 
     data = last_line 
+0

這是不必要的複雜。只需在最初的程序中將結束參數設爲一個空字符串,並且你很好。另外看看這個論點來結束;你錯過了一個字符...... – TisteAndii

+0

這完全取決於你可能想要用這些數據真正做什麼......如果不是僅僅打印它,而是想將它存儲起來進行分析,或者通過正則表達式來提取它信息,那麼你會想整理完整的線。 – donkopotamus

+0

對......我想這個問題的最後一行讓人困惑......但是從他之前的陳述和他的代碼中,我認爲他所要做的只是打印回覆。即使他想保存這些行,使用列表會更有效率,因爲append()的成本已攤銷,收集塊並最後在列表中調用join()。字符串連接,特別是當你可以得到一個大的響應時,將是非常低效的。 – TisteAndii

-2

編輯socket.recv()阻塞和喜歡的人說,你不會在每次調用該方法時得到一個確切的行。因此,套接字正在等待數據,獲取它可以獲取的內容然後返回。當你打印這個時,由於pythons默認結束參數,你可能會得到比預期更多的換行符。所以,從服務器獲取原始的東西,用這個:

import socket 
BUFFER_SIZE = 1024 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.connect(('gump.gatech.edu', 756)) 
try: 
    while (1): 
     data=s.recv(BUFFER_SIZE).decode('utf-8') 
     if not data: break 
     print(data, end="") 
except KeyboardInterrupt: 
    s.close() 
+0

與此答案相反,'socket.recv' **阻塞**,除非套接字具有被明確設置爲非阻塞,或者被關閉,或者存在信號中斷。此外,這個答案不涉及部分線路正在收到。 – donkopotamus

+0

錯誤。 a)'socket.recv' _is_默認爲阻塞,b)''socket.recv'在連接關閉時返回空字符串。 c)空的字符串_is_空。 – mhawke

+0

對。刪除... – TisteAndii

1

解決您的代碼最簡單的方法是將打印接收到的數據沒有添加新線,其中print聲明(Python的2) print()函數(Python 3)默認執行。像這樣:

的Python 2:

print data, 

的Python 3:

print(data, end='') 

現在print不會自己的新行字符添加到每個印刷值的末尾,只有存在的新線在收到的數據將被打印。其結果是每行打印時不會根據每個socket.recv()接收到的數據量進行分割。例如:

from __future__ import print_function 
import socket 

s = socket.socket() 
s.connect(('gump.gatech.edu', 756)) 

while True: 
    data = s.recv(3).decode('utf8') 
    if not data: 
     break # socket closed, all data read 
    print(data, end='') 

在這裏,我已經使用了3非常小的緩衝區大小,這有助於突出問題。

請注意,這隻能解決打印數據的POV問題。如果您想逐行處理數據,則需要自行緩衝傳入的數據,並在收到新行或套接字關閉時處理該行。

+0

這是完美的印刷,但我確實需要將它結合起來。我現在想我會記錄下來並從中完成它。然後使用日誌文件。 – Blessoul

相關問題