Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/353.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在python中从套接字读取JSON?(JSON的增量解析)_Python_Json_Sockets - Fatal编程技术网

如何在python中从套接字读取JSON?(JSON的增量解析)

如何在python中从套接字读取JSON?(JSON的增量解析),python,json,sockets,Python,Json,Sockets,我打开了一个套接字,我想从中读取一些json数据。问题是标准库中的json模块只能从字符串解析(load只读取整个文件并在内部调用load),它甚至看起来在模块内部完全依赖于字符串参数 这对于套接字来说是一个真正的问题,因为您永远无法将其全部读取到字符串,并且在实际解析之前不知道要读取多少字节 所以我的问题是:有没有(简单而优雅的)解决办法?是否还有另一个json库可以增量解析数据?值得我自己写吗 编辑:它是XBMC jsonrpc api。没有信封,我也无法控制信封的格式。每条消息可以在一行上

我打开了一个套接字,我想从中读取一些json数据。问题是标准库中的
json
模块只能从字符串解析(
load
只读取整个文件并在内部调用
load
),它甚至看起来在模块内部完全依赖于字符串参数

这对于套接字来说是一个真正的问题,因为您永远无法将其全部读取到字符串,并且在实际解析之前不知道要读取多少字节

所以我的问题是:有没有(简单而优雅的)解决办法?是否还有另一个json库可以增量解析数据?值得我自己写吗

编辑:它是XBMC jsonrpc api。没有信封,我也无法控制信封的格式。每条消息可以在一行上,也可以在几行上。
我可以编写一些只需要某种形式的getc函数的简单解析器,并使用
s.recv(1)
将其提供给它,但这并不是一个非常pythonic的解决方案,我有点懒得这么做:-)

编辑:如果您没有定义协议,这是没有用的,但在其他上下文中可能有用


假设它是一个流(TCP)套接字,您需要实现自己的消息帧机制(或者使用现有的更高级别协议)。一种简单的方法是将每条消息定义为一个32位整数长度字段,后跟许多字节的数据

发送方:获取JSON数据包的长度,使用
struct
模块将其打包成4个字节,在套接字上发送,然后发送JSON数据包

接收器:重复从套接字读取数据,直到至少有4个字节的数据,使用
struct.unpack
解压长度。从套接字读取数据,直到您至少有那么多数据,这就是您的JSON数据包;剩下的就是下一条消息的长度

如果在某个时刻,您希望通过同一套接字发送由JSON以外的内容组成的消息,那么您可能希望在长度和数据负载之间发送消息类型代码;恭喜你,你又发明了一个协议


另一种稍微标准一点的方法是DJB的协议;它与上面提出的系统非常相似,但是使用文本编码长度而不是二进制长度;它由框架直接支持,例如。

您可以控制json吗?试着把每个对象写成一行。然后根据需要在套接字上执行readline调用


如果从HTTP流获取JSON,请使用
Content-Length
头获取JSON数据的长度。例如:

import httplib
import json

h = httplib.HTTPConnection('graph.facebook.com')
h.request('GET', '/19292868552')
response = h.getresponse()
content_length = int(response.getheader('Content-Length','0'))

# Read data until we've read Content-Length bytes or the socket is closed
data = ''
while len(data) < content_length or content_length == 0:
    s = response.read(content_length - len(data))
    if not s:
        break
    data += s

# We now have the full data -- decode it
j = json.loads(data)
print j
导入httplib
导入json
h=httplib.HTTPConnection('graph.facebook.com')
h、 请求('GET','/19292868552')
response=h.getresponse()
content_length=int(response.getheader('content-length','0'))
#读取数据,直到我们读取了内容长度字节或套接字关闭
数据=“”
而len(data)
浏览XBMC JSON RPC文档,我想您需要一个现有的JSON-RPC库-您可以看看:

如果这不适合任何原因,那么在我看来,每个请求和响应都包含在一个JSON对象中(而不是一个松散的JSON原语,可能是字符串、数组或数字),因此您要查找的信封是定义JSON对象的“{…}”

因此,我会尝试类似(伪代码)的方法:


您可能会发现JSON-RPC在这种情况下很有用。它是一种远程过程调用协议,允许您调用XBMC JSON-RPC公开的方法。您可以在上找到规范。

您想要的(ed)是ijson,一个增量json解析器。 可在以下位置获取:。用法应简单,如(从该页面复制):

(对于那些喜欢自给自足的东西的人来说——从某种意义上说,它只依赖于标准库:我昨天写了一个关于json的小包装器——但这只是因为我不知道ijson。它的效率可能要低得多。)

编辑:由于我发现我的方法(cythonized版本)实际上比ijson有效得多,因此我将其打包为一个独立的库-请参见此处了解一些粗略的基准:


此套接字流是否包括信封?大多数套接字协议都会让您了解流下内容的大小。您是否正在尝试连接到众所周知的json套接字协议?你能控制套接字协议吗?最简单的方法是知道每条消息的大小(就像HTTP有内容长度头一样)。否则,您必须在数据进入时解析数据,以了解数据何时开始和何时结束,而标准库无法帮助您。这可能会起作用,但我仍然必须解析字符串(至少是打开和关闭引号以及转义引号),因为字符串如下:
“\”{"
。我尝试了一些JSONRPC库。其中大多数太复杂,无法在原始TCP连接上运行,或者只能作为服务器运行。我尝试的唯一JSON解析器是标准库中的JSON解析器。我想我仍然不清楚问题的参数。你的应用程序是客户端还是服务器角色?你希望使用原始TCP吗不仅仅是JSON RPC的连接?我的应用程序是一个客户端。服务器响应我的方法调用或发送没有响应的通知。在套接字上发送的所有消息都是JSON对象或数组。这将不起作用,因为:1)JSON对象可以长于4kB 2)对象可以分布在多条线上是的,这是更像是一个示例。不是一个详细的解决方案。可以使用其他库或在此处添加正则表达式。如果不限于套接字。
请求
将使事情变得更容易
import httplib
import json

h = httplib.HTTPConnection('graph.facebook.com')
h.request('GET', '/19292868552')
response = h.getresponse()
content_length = int(response.getheader('Content-Length','0'))

# Read data until we've read Content-Length bytes or the socket is closed
data = ''
while len(data) < content_length or content_length == 0:
    s = response.read(content_length - len(data))
    if not s:
        break
    data += s

# We now have the full data -- decode it
j = json.loads(data)
print j
while not dead:
    read from the socket and append it to a string buffer
    set a depth counter to zero
    walk each character in the string buffer:
        if you encounter a '{':
            increment depth
        if you encounter a '}':
            decrement depth
            if depth is zero:
                remove what you have read so far from the buffer
                pass that to json.loads()
import ijson.backends.python as ijson

for item in ijson.items(file_obj):
    # ...
res = str(s.recv(4096), 'utf-8') # Getting a response as string
res_lines = res.splitlines() # Split the string to an array
last_line = res_lines[-1] # Normally, the last one is the json data
pair = json.loads(last_line)