gpt4 book ai didi

python - 在python中封装套接字数据的正确方法?

转载 作者:行者123 更新时间:2023-12-03 12:05:48 26 4
gpt4 key购买 nike

我正在开发一个通过套接字向其自身的另一个实例发送和接收数据的应用程序,并且我对使用“END”标签封装数据的最有效方法感到好奇。例如,以下是两个用于通过套接字连接进行读取和写入的函数:

def sockWrite(conn, data):
data = data + ":::END"
conn.write(data)

def sockRead(conn):
data = ""
recvdata = conn.read()
while recvdata:
data = data + recvdata
if data.endswith(':::END'):
data = data[:len(data)-6]
break
recvdata = conn.read()
if data == "":
print 'SOCKR: No data')
else:
print 'SOCKR: %s', data)
return data

我基本上是在写上加上“::: END”,因为单次写可能会发生多次读。因此,读取将循环直到它到达“::: END”。

如果数据变量包含字符串“::: END”(碰巧出现在其中一个读取的末尾),则这当然会引起问题。

有没有一种适当的方法来封装数据,并尽可能减少带宽增加?我曾考虑过pickle或json,但担心会增加大量带宽,因为我相信它们会将二进制数据转换为ASCII。我是正确的吗?

谢谢,

最佳答案

零点:您真的需要对此进行优化吗?

通常,您发送相对较小的消息。当您忽略多少以太网,IP和TCP开销以及浪费带宽的RTT时,从512字节的消息中减少60字节通常是很愚蠢的。

另一方面,当您发送大量消息时,通常不需要在同一连接上发送多个消息。

查看常见的Internet协议(protocol),例如HTTP,IMAP等。它们中的大多数使用行定界,易于阅读且易于调试的纯文本。 HTTP可以二进制形式发送“消息的其余部分”,但是在完成发送之后,您必须关闭套接字。

99%的时间,这已经足够了。如果您认为这种情况不够好,我仍然会编写协议(protocol)的文本版本,然后在调试和正常工作后添加一个可选的二进制版本(然后进行测试以查看它是否真的有效)。有所作为)。

同时,您的代码有两个问题。

首先,如您所知,如果您使用":::END"作为定界符,并且您的消息可以在其数据中包含该字符串,则您会感到模棱两可。解决此问题的常用方法是某种形式的转义或引用。举一个非常简单的例子:

def sockWrite(conn, data):
data = data.replace(':', r'\:') + ":::END"
conn.write(data)

现在,在读取端,您只需拉下定界符,然后在消息上添加 replace('r\:', ':')即可。 (当然,仅使用6字节的 ':::END'分隔符来转义每个冒号是浪费的-您也可以只使用未转义的冒号作为定界符,或者编写更复杂的转义机制。)

其次,您说对了“一次写入可能会发生多次读取”是正确的,但对于此一次读取可能会发生多次写入也是正确的。您可以阅读此消息的一半,再读一半。这意味着您不能只使用 endswith;您必须使用 partitionsplit之类的东西,编写可处理多条消息的代码,并编写可存储部分消息的代码,直到下一次通过 read循环。

同时,针对您的具体问题:

Is there a proper way to encapsulate the data with as minimum of bandwidth addition as possible?



当然,至少有三种适当的方法:定界符,前缀或自定界格式。

您已经找到了第一个。随之而来的问题是:除非有一些字符串永远不会出现在您的数据中(例如,人类可读的UTF-8文本中的 '\0'),否则您将无法选择不需要转义的定界符。

像JSON这样的自定界格式是最简单的解决方案。当最后一个打开的支架/支架关闭时,该消息结束,该到下一个了。

或者,您可以为每个消息加上包含长度的 header 作为前缀。这是许多低级协议(protocol)(例如TCP)所做的。最简单的格式之一是 netstring,其中 header 只是长度(以字节为单位),以整数形式表示为普通的以10为基数的字符串,后跟冒号。 netstring协议(protocol)还使用逗号作为定界符,这增加了一些错误检查。

I had thought about pickle or json, but worried that will add a significant amount of bandwidth since I believe they will convert the binary data to ASCII


pickle具有二进制和文本格式。正如 the documentation解释的那样,如果您使用协议(protocol) 23HIGHEST_PROTOCOL,您将获得一个相当有效的二进制格式。

另一方面,JSON仅处理字符串,数字,数组和字典。您必须先将任何二进制数据呈现为字符串(或字符串或数字的数组,或其他形式),然后才能对其进行JSON编码,然后在另一侧进行反转。两种常见的实现方法是base-64和hex,它们分别将数据大小增加了25%和100%,但是如果您确实需要的话,还有更有效的方法。

当然,JSON协议(protocol)本身使用的字符比严格使用的字符多,所有这些引号和逗号等等,以及您为任何字段指定的任何名称均以未压缩的UTF-8格式发送。如果确实有问题,您总是可以用 BSONProtocol BuffersXDR或其他不太浪费的序列化格式替换JSON。

同时, pickle不是自定界的。您必须先将消息分开,然后才能对其进行修补。 JSON是自定界的,但是除非您首先将消息分开,否则不能只使用 json.loads。您将不得不编写更复杂的内容。最简单的方法是在缓冲区上重复调用 raw_decode ,直到获得对象为止。

关于python - 在python中封装套接字数据的正确方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15259578/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com