我在Python 3.5中编写Python脚本,我有一个主机和端口,我想要做的是创建脚本,以便它不断监视提供的主机数据。数据通过TCP流式传输以xml格式分发,标签标记事件的开始和结束。
所以我要做的是基本上监视TCP事件,以便在xml开始和结束标记之间标记新事件,然后检索事件并在我的脚本中相应地处理它。此外,理想情况下,我需要在几毫秒内访问Feed中的新数据。
Feed是一个分发警报的政府Feed,Feed是streaming1.naad-adna.pelmorex.com,端口是8080,我想要做的是监控此Feed以获取新警报,然后才能访问在Python中相应地发出警报并进行处理。 Feed会每分钟发送一次心跳以指示连接处于活动状态。
我认为最好的选择是使用套接字,但我不确定如何在这个特定的用例中实现它们。我没有太多关于TCP提要的经验,而且在我的特定用例下我无法找到很多关于如何在Python中处理TCP提要的在线,我能够处理xml虽然我能够弄清楚如何从TCP提要中提取它。
任何帮助都将不胜感激。
答案 0 :(得分:1)
您的问题中提出了一些技术挑战。
首先,是连接服务器和检索数据的简单问题。正如您在下面的connect()
中看到的那样,这很简单,只需创建一个套接字(s = socket.socket()
)并连接它(s.connect(('hostname', port_number))
)。
下一个问题是以有用的形式检索数据。套接字本身提供.recv()
,但我想要一个类似文件的接口。套接字模块提供了Python独有的方法:.makefile()
。 (return s.makefile('rb')
)
现在我们遇到困难的部分。 XML文档通常每个文件存储一个文档,或者每个TCP传输存储一个文档。因此,文档结尾很容易通过文件结束指示或Content-Length:
标题发现。因此,Python XML API都没有一种机制可以在一个文件或一个字符串中处理多个XML文档。我写了xml_partition()
来解决这个问题。 xml_partition()
使用来自类文件对象的数据,并从流中生成每个XML文档。 (注意:必须将XML文档压在一起。在最终>
之后不允许有空格。
最后,有一个简短的测试程序(alerts()
)连接到流并读取一些XML文档,将每个文档存储到自己的文件中。
这里,整体上是用于从国家警报聚合& amp; amp; amp; amp; amp; amp; amp; amp; amp; Pelmorex的传播系统。
import socket
import xml.etree.ElementTree as ET
def connect():
'Connect to pelmorex data stream and return a file-like object'
# Set up the socket
s = socket.socket()
s.connect(('streaming1.naad-adna.pelmorex.com', 8080))
return s.makefile('rb')
# We have to consume the XML data in bits and pieces
# so that we can stop precisely at the boundary between
# streamed XML documents. This function ensures that
# nothing follows a '>' in any XML fragment.
def partition(s, pattern):
'Consume a file-like object, and yield parts defined by pattern'
data = s.read(2048)
while data:
left, middle, data = data.partition(pattern)
while left or middle:
yield left
yield middle
left, middle, data = data.partition(pattern)
data = s.read(2048)
# Split the incoming XML stream into fragments (much smaller
# than an XML document.) The end of each XML document
# is guaranteed to align with the end of a fragment.
# Use an XML parser to determine the actual end of
# a document. Whenever the parser signals the end
# of an XML document, yield what we have so far and
# start a new parser.
def xml_partition(s):
'Read multiple XML documents from one data stream'
parser = None
for part in partition(s, b'>'):
if parser is None:
parser = ET.XMLPullParser(['start', 'end'])
starts = ends = 0
xml = []
xml.append(part)
parser.feed(part)
for event, elem in parser.read_events():
starts += event == "start"
ends += event == "end"
if starts == ends > 0:
# We have reached the end of the XML doc
parser.close()
parser = None
yield b''.join(xml)
# Typical usage:
def alerts():
for i, xml in enumerate(xml_partition(connect())):
# The XML is a bytes object that contains the undecoded
# XML stream. You'll probably want to parse it and
# somehow display the alert.
# I'm just saving it to a file.
with open('alert%d.xml' % i, 'wb') as fp:
fp.write(xml)
if i == 3:
break
def test():
# A test function that uses multiple XML documents in one
# file. This avoids the wait for a natural-disaster alert.
with open('multi.xml', 'rb') as fp:
print(list(xml_partition(fp)))
alerts()