尾部-f登录服务器,处理数据,然后通过扭曲服务到客户端

jsu*_*csy 9 python twisted

目标:在客户端的wxPython GUI中显示来自服务器的数据

Twisted的新人.我有一个在Windows 7客户端上运行的wxPython GUI,我有一个在Ubuntu服务器上运行的程序,它生成一个日志.我目前的尝试是尾随日志,将输出传输到扭曲的服务器,然后将满足我的正则表达式条件的任何数据提供给客户端.我已经打开隧道了,所以我不需要用SSH复杂化.我已经运行了以下代码块,但它只服务于输入中的第一行.我知道我需要继续检查新行的输入然后将其写入传输,但我不确定如何在不断开连接的情况下执行此操作.

我一直无法找到足够的信息来修补完整的解决方案.我也尝试过使用套接字和文件IO的各种其他方法,但我认为Twisted似乎是解决这个问题的好工具.我是在正确的轨道上吗?任何建议表示赞赏 谢谢

#! /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()
Run Code Online (Sandbox Code Playgroud)

为了回答第一条评论,我还尝试从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()
Run Code Online (Sandbox Code Playgroud)

Jea*_*one 7

你有一些不同的容易分开的目标,你想在这里实现.首先,我将谈谈观看日志文件.

你的发电机有几个问题.其中一个很大 - 它叫time.sleep(0.1).该sleep功能块传递给它的时间量.当它被阻塞时,调用它的线程不能做任何其他事情(毕竟这大概是"阻塞"意味着什么).你在LogProtocol.connectionMade调用的同一个线程中迭代生成器(自connectionMade调用以来follow). LogProtocol.connectionMade在Twisted反应器运行的同一个线程中调用,因为Twisted大致是单线程的.

所以,你正在通过sleep电话阻止反应堆.只要睡眠阻塞反应堆,反应堆就无法做任何事情 - 比如通过套接字发送字节.顺便说一句,阻止是传递性的.这LogProtocol.connectionMade是一个更大的问题:它无限循环,睡眠和阅读.因此它无限期地阻塞了反应堆.

您需要从文件中读取行而不会阻塞.你可以通过轮询来做到这一点 - 这实际上是你现在采取的方法 - 但是避免了睡眠呼叫.使用reactor.callLater安排未来从文件读取:

def follow(fObj):
    line = fObj.readline()
    reactor.callLater(0.1, follow, fObj)

follow(open(filename))
Run Code Online (Sandbox Code Playgroud)

您还可以让LoopingCall处理使这个循环永久运行的部分:

def follow(fObj):
    line = fObj.readline()

from twisted.internet.task import LoopingCall

loop = LoopingCall(follow, open(filename))
loop.start(0.1)
Run Code Online (Sandbox Code Playgroud)

这些中的任何一个都可以让您在不阻塞反应器的情况下从文件中读取新行.当然,他们只是在阅读后才将线放在地板上.这引出了我的第二个问题......

您需要对文件中新行的外观做出反应.大概你想把它写出来给你的连接.这并不太难:"反应"非常简单,通常只是意味着调用一个函数或一个方法.在这种情况下,最简单的方法是LogProtocol设置日志跟踪并提供一个回调对象来处理它们出现的行.考虑follow从上面对该功能的这种轻微调整:

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)
Run Code Online (Sandbox Code Playgroud)

现在,您可以非阻塞地轮询日志文件以查找新行,了解实际显示的行.这很容易与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)
Run Code Online (Sandbox Code Playgroud)

最后一个细节是,您可能希望在连接丢失时停止观看文件:

    def connectionLost(self, reason):
        self.loop.stop()
Run Code Online (Sandbox Code Playgroud)

因此,当使用简单的方法调用找到协议时,此解决方案通过使用LoopingCall而不是time.sleep将行推送到协议来避免阻塞.