处理套接字连接的最佳方法是什么,我需要var data
以换行符结束\n
?
我使用下面的代码,但有时tcp
数据包会 chunked ,并且匹配data.endswith("\n")
需要很长时间。
我还尝试了其他方法,例如,如果它不以\n
结尾,则保存最后一行,并在下一个循环中将其附加到data
。但这也不起作用,因为多个数据包被分块,第一和第二部分不匹配。
我无法控制另一端,它基本上会发送以\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 = ""
" 正常" data
:
line1\r\n
line2\r\n
line3\r\n
分块 data
的示例:
line1\r\n
line2\r\n
lin
答案 0 :(得分:4)
如果您要将原始输入作为行处理,则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()
答案 1 :(得分:1)
使用 socket.socket.makefile() 将套接字包装在实现 Text I/O 的类中。它处理缓冲、字节和字符串之间的转换,并允许您遍历行。记得刷新任何写入。
示例:
#!/usr/bin/env python3
import socket, threading, time
def client(addr):
with socket.create_connection(addr) as conn:
conn.sendall(b'aaa')
time.sleep(1)
conn.sendall(b'bbb\n')
time.sleep(1)
conn.sendall(b'cccddd\n')
time.sleep(1)
conn.sendall(b'eeefff')
time.sleep(1)
conn.sendall(b'\n')
conn.shutdown(socket.SHUT_WR)
response = conn.recv(1024)
print('client got %r' % (response,))
def main():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as listen_socket:
listen_socket.bind(('localhost', 0))
listen_socket.listen(1)
addr = listen_socket.getsockname()
threading.Thread(target=client, args=(addr,)).start()
conn, _addr = listen_socket.accept()
conn_file = conn.makefile(mode='rw', encoding='utf-8')
for request in conn_file:
print('server got %r' % (request,))
conn_file.write('response1\n')
conn_file.flush()
if __name__ == '__main__':
main()
$ ./example.py
server got 'aaabbb\n'
server got 'cccddd\n'
server got 'eeefff\n'
client got b'response1\n'
$
答案 2 :(得分:0)
我没有测试过这段代码,但它应该可以运行:
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:修复了问题。
答案 3 :(得分:0)
您是否接受不同的联系?或者它是一个数据流,由\r\n
分开?
接受多个连接时,您需要等待与s.accept()
的连接,然后处理其所有数据。获得所有数据包后,处理其数据,然后等待下一次连接。
那你做什么取决于每个数据包的结构。
(例如:https://wiki.python.org/moin/TcpCommunication)
如果您正在使用数据流,那么您应该处理每一行'你在一个单独的线程中找到了,而你继续在另一个线程中消费。
修改强>
所以,如果我的情况正确的话;一个连接,数据是由\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 = ""
编辑2:糟糕,代码错误
答案 4 :(得分:-1)
你似乎基本上想从套接字读取行。也许您最好不要使用低级recv
来电,只需使用sock.makefile()
并将结果视为常规文件,您可以在其中读取以下行:from line in sfile: ...
留下延迟/块问题。这可能是由发送方Nagle's algorithm引起的。尝试禁用:
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)