2011-11-16 17 views
9

Mục tiêu: Hiển thị dữ liệu từ máy chủ trong GUI wxPython trên máy kháchTail -f đăng nhập vào máy chủ, xử lý dữ liệu, sau đó phục vụ cho khách hàng thông qua twisted

Người mới đến Xoắn. Tôi có một GUI wxPython chạy trên một máy khách Windows 7, và tôi có một chương trình đang chạy trên một máy chủ Ubuntu để tạo ra một bản ghi. Nỗ lực hiện tại của tôi là kết nối nhật ký, đưa đầu ra đến một máy chủ bị xoắn, sau đó phục vụ bất kỳ dữ liệu nào đáp ứng các điều kiện regex của tôi cho máy khách. Tôi đã có một đường hầm mở, vì vậy tôi không cần phải phức tạp với SSH. Tôi đã nhận được khối mã sau đang chạy, nhưng nó chỉ phục vụ dòng đầu tiên trong đầu vào. Tôi biết tôi cần phải tiếp tục kiểm tra đầu vào cho một dòng mới và sau đó ghi nó vào vận chuyển, nhưng tôi không chắc chắn làm thế nào để làm điều đó mà không vi phạm kết nối.

Tôi chưa thể tìm đủ thông tin để vá một giải pháp đầy đủ với nhau. Tôi cũng đã thử các phương pháp khác nhau bằng cách sử dụng ổ cắm và tập tin IO, nhưng tôi nghĩ Twisted có vẻ là một công cụ tốt cho vấn đề này. Có phải tôi đang trên đường ray bên phải không? Bất kỳ đề xuất nào được đánh giá cao. Cảm ơn

#! /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() 

Để trả lời nhận xét đầu tiên, tôi cũng đã thử đọc nhật ký từ bên trong Python, chương trình bị treo. Mã sau:

#! /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

Bạn đã xem xét đọc nhật ký từ bên trong python, chứ không phải là đường dẫn đầu ra từ 'đuôi'? – Velociraptors

+0

Đã cố gắng để làm việc này cũng như sử dụng một máy phát điện, chương trình treo cứng. Dường như với tôi rằng việc vận chuyển và máy phát điện đang chờ người khác kết thúc. Mã được hiển thị ở trên. Có cách nào tốt hơn để làm điều này hơn bằng cách sử dụng một máy phát điện? – jsucsy

Trả lời

7

Bạn có một vài mục tiêu khác nhau được phân tách dễ dàng mà bạn đang cố gắng đạt được ở đây. Đầu tiên, tôi sẽ nói về việc xem tệp nhật ký.

Máy phát của bạn có một vài sự cố. Một trong số đó là lớn - nó gọi là time.sleep(0.1). Các khối chức năng sleep cho khoảng thời gian được truyền cho nó. Trong khi nó đang chặn, chuỗi được gọi là nó không thể làm bất cứ điều gì khác (đó là khoảng những gì "chặn" có nghĩa là, sau khi tất cả). Bạn đang lặp qua trình tạo trong cùng một chuỗi với tên LogProtocol.connectionMade được gọi trong (từ connectionMade cuộc gọi follow). LogProtocol.connectionMade được gọi trong cùng một luồng với lò phản ứng Xoắn đang hoạt động, bởi vì Xoắn là chỉ đơn luồng.

Vì vậy, bạn đang chặn lò phản ứng bằng các cuộc gọi sleep. Miễn là ngủ đang chặn lò phản ứng, lò phản ứng không thể làm bất cứ điều gì - như gửi byte qua ổ cắm. Blocking là transitive, nhân tiện. Vì vậy, LogProtocol.connectionMade là một vấn đề lớn hơn: nó lặp đi lặp lại vô thời hạn, ngủ và đọc. Vì vậy, nó chặn lò phản ứng vô thời hạn.

Bạn cần phải đọc các dòng từ tệp mà không chặn. Bạn có thể làm điều này bằng cách bỏ phiếu - đó là cách tiếp cận hiệu quả mà bạn đang thực hiện - nhưng tránh cuộc gọi ngủ. Sử dụng reactor.callLater lịch trình tương lai đọc từ tập tin:

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

follow(open(filename)) 

Bạn cũng có thể cho LoopingCall thỏa thuận với các phần đó làm cho điều này một vòng lặp chạy mãi mãi:

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

from twisted.internet.task import LoopingCall 

loop = LoopingCall(follow, open(filename)) 
loop.start(0.1) 

Hoặc trong số này sẽ cho phép bạn đọc mới dòng từ tập tin theo thời gian mà không ngăn chặn các lò phản ứng. Tất nhiên, cả hai đều chỉ cần thả dòng trên sàn sau khi họ đọc nó. Điều này dẫn tôi đến vấn đề thứ hai ...

Bạn cần phản ứng với sự xuất hiện của một dòng mới trong tệp. Có lẽ bạn muốn viết nó ra để kết nối của bạn. Đây không phải là quá khó: "phản ứng" là khá dễ dàng, nó thường chỉ có nghĩa là gọi một hàm hoặc một phương thức. Trong trường hợp này, dễ nhất là để LogProtocol thiết lập nhật ký sau và cung cấp đối tượng gọi lại để xử lý các dòng khi chúng xuất hiện.Xem xét điều chỉnh nhẹ này cho follow chức năng từ trên cao:

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) 

Bây giờ bạn không blockingly có thể thăm dò ý kiến ​​một log file cho dòng mới học khi ai đã thực sự thể hiện lên. Đây là đơn giản để tích hợp với 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) 

Một chi tiết cuối cùng là bạn có thể muốn dừng lại xem các tập tin khi kết nối bị mất:

def connectionLost(self, reason): 
     self.loop.stop() 

Vì vậy, giải pháp này tránh được chặn bởi sử dụng LoopingCall thay vì time.sleep và đẩy đường vào giao thức khi chúng được tìm thấy bằng cách sử dụng các cuộc gọi phương thức đơn giản.

+0

Giải thích tuyệt vời, cảm ơn bạn. Hoạt động đẹp mắt. – jsucsy

Các vấn đề liên quan