Python 处理以换行符结尾的套接字数据

Python 处理以换行符结尾的套接字数据,python,python-2.7,python-3.x,sockets,tcp,Python,Python 2.7,Python 3.x,Sockets,Tcp,当我需要var数据以换行符结束时,处理套接字连接的最佳方法是什么? 我正在使用下面的代码,但有时tcp数据包被分块,需要很长时间才能匹配data.endswith(“\n”)。 我也尝试过其他方法,比如如果最后一行不是以\n结尾,则保存它,并将其附加到下一个循环的数据中。但这也不起作用,因为多个数据包被分块,并且第一部分和第二部分不匹配。 我无法控制另一端,它基本上发送以\r\n结尾的多行 任何建议都欢迎,因为我对套接字连接没有太多的知识 def receive_bar_updates(s):

当我需要var
数据
以换行符结束时,处理套接字连接的最佳方法是什么? 我正在使用下面的代码,但有时
tcp
数据包被分块,需要很长时间才能匹配
data.endswith(“\n”)
。 我也尝试过其他方法,比如如果最后一行不是以
\n
结尾,则保存它,并将其附加到下一个循环的
数据中。但这也不起作用,因为多个数据包被分块,并且第一部分和第二部分不匹配。
我无法控制另一端,它基本上发送以
\r\n
结尾的多行

任何建议都欢迎,因为我对套接字连接没有太多的知识

def receive_bar_updates(s):
    global all_bars
    data = ''
    buffer_size = 4096
    while True:
        data += s.recv(buffer_size)
        if not data.endswith("\n"):
            continue
        lines = data.split("\n")
        lines = filter(None, lines)
        for line in lines:
            if line.startswith("BH") or line.startswith("BC"):
                symbol = str(line.split(",")[1])
                all_bars[symbol].append(line)
                y = Thread(target=proccess_bars, kwargs={'symbol': symbol})
                y.start()
        data = ""
“正常”数据的示例:

line1\r\n
line2\r\n
line3\r\n
line1\r\n
line2\r\n
lin
分块的
数据的示例:

line1\r\n
line2\r\n
line3\r\n
line1\r\n
line2\r\n
lin

基本上,您似乎想要从套接字读取行。也许您最好不要使用低级的
recv
调用,而只使用
sock.makefile()
并将结果视为一个常规文件,您可以从中读取以下行:
从sfile中的行:…

这就留下了延迟/块问题。这可能是由发送端的错误引起的。尝试禁用该选项:

sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

基本上,您似乎想要从套接字读取行。也许您最好不要使用低级的
recv
调用,而只使用
sock.makefile()
并将结果视为一个常规文件,您可以从中读取以下行:
从sfile中的行:…

这就留下了延迟/块问题。这可能是由发送端的错误引起的。尝试禁用该选项:

sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

我尚未测试此代码,但它应该可以工作:

def receive_bar_updates(s):
    global all_bars
    data = ''
    buf = ''
    buffer_size = 4096
    while True:
        if not "\r\n" in data:  # skip recv if we already have another line buffered.
            data += s.recv(buffer_size)
        if not "\r\n" in data:
            continue
        i = data.rfind("\r\n")
        data, buf = data[:i+2], data[i+2:]
        lines = data.split("\r\n")
        lines = filter(None, lines)
        for line in lines:
            if line.startswith("BH") or line.startswith("BC"):
                symbol = str(line.split(",")[1])
                all_bars[symbol].append(line)
                y = Thread(target=proccess_bars, kwargs={'symbol': symbol})
                y.start()
        data = buf
编辑:忘了提一下,我只修改了接收数据的代码,我不知道函数的其余部分(从
lines=data.split(“\n”)
)是用来做什么的

编辑2:现在换行符使用“\r\n”而不是“\n”


编辑3:修复了一个问题。

我还没有测试过这段代码,但它应该可以工作:

def receive_bar_updates(s):
    global all_bars
    data = ''
    buf = ''
    buffer_size = 4096
    while True:
        if not "\r\n" in data:  # skip recv if we already have another line buffered.
            data += s.recv(buffer_size)
        if not "\r\n" in data:
            continue
        i = data.rfind("\r\n")
        data, buf = data[:i+2], data[i+2:]
        lines = data.split("\r\n")
        lines = filter(None, lines)
        for line in lines:
            if line.startswith("BH") or line.startswith("BC"):
                symbol = str(line.split(",")[1])
                all_bars[symbol].append(line)
                y = Thread(target=proccess_bars, kwargs={'symbol': symbol})
                y.start()
        data = buf
编辑:忘了提一下,我只修改了接收数据的代码,我不知道函数的其余部分(从
lines=data.split(“\n”)
)是用来做什么的

编辑2:现在换行符使用“\r\n”而不是“\n”


编辑3:修复了一个问题。

您是否接受不同的连接?还是由
\r\n
分割的一个数据流

当接受多个连接时,您需要等待使用
s.accept()的连接,然后处理其所有数据。当您拥有所有数据包时,处理其数据,并等待下一次连接。
然后,您所做的取决于每个数据包的结构。
(例如:)

如果您使用的是一个数据流,那么您可能应该在一个单独的线程中处理您找到的每一个“行”,同时继续使用另一个线程

编辑: 所以,如果我知道你的情况是正确的;一个连接,数据是由
\r\n
分割的字符串,以
\n
结尾。但是,数据与您期望的不一致,而是无限循环等待
\n

据我所知,套接字接口以空数据结果结束。因此,最后一个缓冲区可能以
\n
结束,但随后继续获取
None
对象,试图找到另一个
\n

相反,请尝试添加以下内容:

if not data:
    break
完整代码:

def receive_bar_updates(s):
    global all_bars
    data = ''
    buffer_size = 4096
    while True:
        data += s.recv(buffer_size)
        if not data:
            break
        if not data.endswith("\n"):
            continue
        lines = data.split("\n")
        lines = filter(None, lines)
        for line in lines:
            if line.startswith("BH") or line.startswith("BC"):
                symbol = str(line.split(",")[1])
                all_bars[symbol].append(line)
                y = Thread(target=proccess_bars, kwargs={'symbol': symbol})
                y.start()
        data = ""

Edit2:Oops,错误代码

您是否接受不同的连接?还是由
\r\n
分割的一个数据流

当接受多个连接时,您需要等待使用
s.accept()的连接,然后处理其所有数据。当您拥有所有数据包时,处理其数据,并等待下一次连接。
然后,您要做什么取决于每个包的结构。
(例如:)

如果您使用的是一个数据流,那么您可能应该在一个单独的线程中处理您找到的每一个“行”,同时继续使用另一个线程

编辑: 所以,如果我知道你的情况是正确的;一个连接,数据是由
\r\n
分割的字符串,以
\n
结尾。但是,数据与您期望的不一致,而是无限循环等待
\n

据我所知,套接字接口以空数据结果结束。因此,最后一个缓冲区可能以
\n
结束,但随后继续获取
None
对象,试图找到另一个
\n

相反,请尝试添加以下内容:

if not data:
    break
完整代码:

def receive_bar_updates(s):
    global all_bars
    data = ''
    buffer_size = 4096
    while True:
        data += s.recv(buffer_size)
        if not data:
            break
        if not data.endswith("\n"):
            continue
        lines = data.split("\n")
        lines = filter(None, lines)
        for line in lines:
            if line.startswith("BH") or line.startswith("BC"):
                symbol = str(line.split(",")[1])
                all_bars[symbol].append(line)
                y = Thread(target=proccess_bars, kwargs={'symbol': symbol})
                y.start()
        data = ""

Edit2:Oops,错误代码

如果您有一个原始输入要作为行处理,io模块是您的朋友,因为它将在行中对数据包进行低级组装

您可以使用:

class SocketIO(io.RawIOBase):
    def __init__(self, sock):
        self.sock = sock
    def read(self, sz=-1):
        if (sz == -1): sz=0x7FFFFFFF
        return self.sock.recv(sz)
    def seekable(self):
        return False
它比
endswith('\n')
更健壮,因为如果一个数据包包含嵌入式换行符(
'ab\ncd'
),io模块将正确处理它。您的代码可能会变成:

def receive_bar_updates(s):
    global all_bars
    data = ''
    buffer_size = 4096
    fd = SocketIO(s)  # fd can be used as an input file object

    for line in fd:
        if should_be_rejected_by_filter(line): continue # do not know what filter does...
        if line.startswith("BH") or line.startswith("BC"):
            symbol = str(line.split(",")[1])
            all_bars[symbol].append(line)
            y = Thread(target=proccess_bars, kwargs={'symbol': symbol})
            y.start()

如果您有一个原始输入,您希望将其作为行处理,那么io模块就是您的朋友,因为它将在行中对数据包进行低级组装

您可以使用:

class SocketIO(io.RawIOBase):
    def __init__(self, sock):
        self.sock = sock
    def read(self, sz=-1):
        if (sz == -1): sz=0x7FFFFFFF
        return self.sock.recv(sz)
    def seekable(self):
        return False
它比
endswith('\n')
更健壮,因为如果一个数据包包含嵌入式换行符(
'ab\ncd'
),io模块将正确处理它。您的代码可能会变成:

def receive_bar_updates(s):
    global all_bars
    data = ''
    buffer_size = 4096
    fd = SocketIO(s)  # fd can be used as an input file object

    for line in fd:
        if should_be_rejected_by_filter(line): continue # do not know what filter does...
        if line.startswith("BH") or line.startswith("BC"):
            symbol = str(line.split(",")[1])
            all_bars[symbol].append(line)
            y = Thread(target=proccess_bars, kwargs={'symbol': symbol})
            y.start()
用于将套接字包装在实现的类中。它处理缓冲、字节和字符串之间的转换,并允许您对行进行迭代。记住刷新任何写入

例如:

#/usr/bin/env蟒蛇3
导入套接字、线程、时间
def客户端(地址):
使用套接字。创建_连接(addr)作为连接:
康涅狄格州森达尔(b)