2011-11-16 68 views
9

目標服務到客戶端的顯示數據從服務器中的wxPython GUI客戶端尾-f登錄服務器,處理數據,然後通過捻

新人到扭曲。我有一個在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() 

要回答第一條評論,我也試着從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() 
+0

您是否考慮過從python內讀取日誌,而不是從'tail'輸出管道? – Velociraptors

+0

已嘗試使用生成器來處理此問題,程序掛起。在我看來,運輸工具和發電機正在等待另一方完成。上面顯示的代碼。有沒有比使用發生器更好的方法來做到這一點? – jsucsy

回答

7

你有幾個不同的容易分離的目標,你試圖在這裏實現。首先,我會談論看日誌文件。

您的發電機有幾個問題。其中一個很大 - 它叫time.sleep(0.1)sleep功能塊將傳遞給它的時間量。當它被阻塞時,調用它的線程無法做任何其他事情(畢竟這就是「阻塞」的意思)。您在調用LogProtocol.connectionMade所用的線程中迭代生成器(因爲connectionMade調用了follow)。在Twisted反應器運行的同一線程中調用LogProtocol.connectionMade,因爲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設置日誌並提供一個回調對象來處理出現的行。考慮這個稍作調整的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) 

現在你可以不阻擋地輪詢日誌文件以新行當一個實際上已經顯示了學習。這是一個簡單的與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,並在使用簡單方法調用找到它們時將協議線路推送至協議。

+0

優秀的解釋,謝謝。精美的作品。 – jsucsy