2016-01-21 65 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

相关问题