Python Tail-f登录服务器,处理数据,然后通过twisted服务于客户端
目标:在客户端的wxpythongui中显示来自服务器的数据 新来者扭曲。我有一个在Windows7客户机上运行的wxPython GUI,还有一个在Ubuntu服务器上运行的程序,可以生成日志。我当前的尝试是跟踪日志,将输出通过管道传输到twisted服务器,然后将满足我的正则表达式条件的任何数据提供给客户端。我已经打开了一个隧道,所以我不需要用SSH使事情复杂化。我已经运行了下面的代码块,但它只服务于输入的第一行。我知道我需要不断检查输入的换行符,然后将其写入传输,但我不知道如何在不中断连接的情况下完成这项工作 我无法找到足够的信息来修补完整的解决方案。我也尝试过使用套接字和文件IO的各种其他方法,但我认为Twisted似乎是解决这个问题的一个好工具。我走对了吗?欢迎提出任何建议。谢谢Python Tail-f登录服务器,处理数据,然后通过twisted服务于客户端,python,twisted,Python,Twisted,目标:在客户端的wxpythongui中显示来自服务器的数据 新来者扭曲。我有一个在Windows7客户机上运行的wxPython GUI,还有一个在Ubuntu服务器上运行的程序,可以生成日志。我当前的尝试是跟踪日志,将输出通过管道传输到twisted服务器,然后将满足我的正则表达式条件的任何数据提供给客户端。我已经打开了一个隧道,所以我不需要用SSH使事情复杂化。我已经运行了下面的代码块,但它只服务于输入的第一行。我知道我需要不断检查输入的换行符,然后将其写入传输,但我不知道如何在不中断连接
#! /usr/bin/python
import optparse, os, sys
from twisted.internet.protocol import ServerFactory, Protocol
def parse_args():
usage = """usage: %prog [options]
"""
parser = optparse.OptionParser(usage)
help = "The port to listen on. Default to a random available port."
parser.add_option('--port', type='int', help=help)
help = "The interface to listen on. Default is localhost."
parser.add_option('--iface', help=help, default='localhost')
options =parser.parse_args()
return options#, log_file
class LogProtocol(Protocol):
def connectionMade(self):
for line in self.factory.log:
self.transport.write(line)
class LogFactory(ServerFactory):
protocol = LogProtocol
def __init__(self,log):
self.log = log
def main():
log = sys.stdin.readline()
options, log_file = parse_args()
factory = LogFactory(log)
from twisted.internet import reactor
port = reactor.listenTCP(options.port or 0, factory,
interface=options.iface)
print 'Serving %s on %s.' % (log_file, port.getHost())
reactor.run()
if __name__ == '__main__':
main()
为了回答第一条评论,我还尝试从Python中读取日志,程序挂起。代码如下:
#! /usr/bin/python
import optparse, os, sys, time
from twisted.internet.protocol import ServerFactory, Protocol
def parse_args():
usage = """ usage: %prog [options]"""
parser = optparse.OptionParser(usage)
help = "The port to listen on. Default to a random available port"
parser.add_option('--port', type='int', help=help, dest="port")
help = "The logfile to tail and write"
parser.add_option('--file', help=help, default='log/testgen01.log',dest="logfile")
options = parser.parse_args()
return options
class LogProtocol(Protocol):
def connectionMade(self):
for line in self.follow():
self.transport.write(line)
self.transport.loseConnection()
def follow(self):
while True:
line = self.factory.log.readline()
if not line:
time.sleep(0.1)
continue
yield line
class LogFactory(ServerFactory):
protocol = LogProtocol
def __init__(self,log):
self.log = log
def main():
options, log_file = parse_args()
log = open(options.logfile)
factory = LogFactory(log)
from twisted.internet import reactor
port = reactor.listenTCP(options.port or 0, factory) #,interface=options.iface)
print 'Serving %s on %s.' % (options.logfile, port.getHost())
reactor.run()
if __name__ == '__main__':
main()
你有几个不同的容易分离的目标,你正试图在这里实现。首先,我将讨论如何查看日志文件 你的发电机有几个问题。其中一个很大,它调用
time.sleep(0.1)
。sleep
功能块用于计算传递给它的时间量。当它阻塞时,调用它的线程不能做任何其他事情(毕竟,这大致就是“阻塞”的意思)。您在与LogProtocol相同的线程中迭代生成器。将在中调用connectionMade
(因为connectionMade
调用follow
)LogProtocol.connectionMade
在Twisted reactor运行的同一线程中被调用,因为Twisted基本上是单线程的
所以,你用sleep
调用阻塞了反应器。只要睡眠阻塞了反应器,反应器就不能做任何事情,比如通过套接字发送字节。顺便说一下,阻塞是可传递的。因此,LogProtocol.connectionMade
是一个更大的问题:它无限期地迭代,睡眠和阅读。所以它会无限期地阻塞反应堆
您需要在不阻塞的情况下从文件中读取行。你可以通过轮询来做到这一点——这是你现在正在采取的有效方法——但要避免睡眠呼叫。使用reactor.callLater
计划将来对文件的读取:
def follow(fObj):
line = fObj.readline()
reactor.callLater(0.1, follow, fObj)
follow(open(filename))
您还可以让LoopingCall
处理使循环永久运行的部分:
def follow(fObj):
line = fObj.readline()
from twisted.internet.task import LoopingCall
loop = LoopingCall(follow, open(filename))
loop.start(0.1)
这两种方法都可以让您在不阻塞反应器的情况下从文件中读取新行。当然,他们两人都只是在读完后把绳子扔到地板上。这就引出了第二个问题
您需要对文件中新行的外观作出反应。大概你想把它写在你的连接上。这并不难:“反应”非常简单,它通常只意味着调用函数或方法。在这种情况下,最简单的方法是让LogProtocol
设置日志跟踪,并提供回调对象来处理出现的行。请考虑上述对def follow(fObj, gotLine):
line = fObj.readline()
if line:
gotLine(line)
def printLine(line):
print line
loop = LoopingCall(follow, open(filename), printLine)
loop.start(0.1)
现在,您可以无阻塞地轮询日志文件中的新行,并了解其中一行何时实际出现。这很容易与LogProtocol
集成
class LogProtocol(Protocol):
def connectionMade(self):
self.loop = LoopingCall(follow, open(filename), self._sendLogLine)
self.loop.start()
def _sendLogLine(self, line):
self.transport.write(line)
最后一个细节是,您可能希望在连接断开时停止监视文件:
def connectionLost(self, reason):
self.loop.stop()
因此,此解决方案通过使用
LoopingCall
而不是time.sleep
来避免阻塞,并在使用简单方法调用时将行推送到协议中。您是否考虑过从python中读取日志,我们没有通过管道从tail
输出,而是尝试使用生成器来解决这个问题,程序挂起。在我看来,运输和发电机都在等待另一个完成。上面显示的代码。有没有比使用发电机更好的方法?