如何使用来自套接字的数据实现webpush?

时间:2011-10-03 22:20:49

标签: python http sockets streaming twisted

这是我目前的代码:

#!/usr/bin/env python
from twisted.application import internet, service
from twisted.application.service import IServiceMaker, MultiService
from twisted.protocols import basic
from twisted.internet  import reactor, protocol, defer
from twisted.internet.protocol import DatagramProtocol
import datetime

class WebPUSH(basic.LineReceiver):
    logTemplate = '''
      <script type="text/javascript">
         pushHandler.addLi('%s')
      </script>
    '''
    def __init__(self):
        self.gotRequest = False

    def lineReceived(self, line):
        if not self.gotRequest:
            self.startResponse()
            self.gotRequest = True

    def startResponse(self):
        self.sendLine('HTTP/1.1 200 OK')
        self.sendLine('Content-Type: text/html; charset=utf-8')
        self.sendLine('')
        f = open('index.html', 'r')
        self.transport.write( ''.join(f.read()) )
        f.close()
        self.logTime()

    def logTime(self):
        self.sendLine( self.logTemplate % datetime.datetime.now() )
        #reactor.callLater(2, self.logTime)

class Echo(DatagramProtocol):

    def datagramReceived(self, data, (host, port)):
        WebPUSH.logTime()
        print "received %r from %s:%d" % (data, host, port)
        self.transport.write(data, (host, port))

if __name__ == '__main__':    
    f = protocol.ServerFactory()
    f.protocol = WebPUSH
    reactor.listenTCP(8080, f)
    reactor.listenUDP(9999, Echo())

    reactor.run()

正如您所看到的,我正在尝试在收到数据时从Echo调用WebPUSH中的方法。因为我从未实际实例化WebPUSH,所以看起来我不能轻易调用此方法。我尝试将其转换为使用多服务方法,但这似乎不起作用,虽然我确信我做错了。

对于像这样的扭曲或至少这样的多服务,没有(据我可以谷歌)任何好的例子。

任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:0)

Echo实例需要WebPUSH协议实例才能调用.logTime()

您需要维护loggers列表,例如main()

...
f.loggers = []
echo = Echo()
echo.loggers = f.loggers
...

WebPUSH.connectionMade中添加,在WebPUSH.connectionLost中删除:

def connectionMade(self):
    self.factory.loggers.append(self)

def connectionLost(self, reason):
    self.factory.loggers.remove(self)

然后在Echo.datagramReceived

for time_logger in self.loggers:
    time_logger.logTime()

答案 1 :(得分:0)

user970077,我博客中的示例是一个简化的演示,用于展示webpush的工作原理。以下是您要做的事情(纳入JFB建议):

#!/usr/bin/env python
from twisted.protocols import basic
from twisted.internet  import reactor, protocol, defer
import datetime

class WebPUSH(basic.LineReceiver):
    logTemplate = '''
      <script type="text/javascript">
         pushHandler.addLi('%s')
      </script>
    '''    
    def connectionMade(self):
       self.factory.listeners.append(self)
       self.startResponse()

    def connectionLost(self, reason):
        self.factory.listeners.remove(self)

    def lineReceived(self, line):
        self.sendLine( self.logTemplate % line )

    def startResponse(self):
        self.sendLine('HTTP/1.1 200 OK')
        self.sendLine('Content-Type: text/html; charset=utf-8')
        self.sendLine('')
        with open('index.html', 'r') as f:
            self.transport.write( ''.join(f.read()) )


class WebPushFactory(protocol.ServerFactory):

    protocol = WebPUSH

    def __init__(self):
        self.listeners = []


class Echo(protocol.DatagramProtocol):

    def __init__(self, listeners):
        self.listeners = listeners

    def datagramReceived(self, data, (host, port)):
        msg = '[%s:%s] %s' % (host, port, data)
        for listener in self.listeners:
            # udp is not necessarily line-oriented
            # so we can:
            # 1) feed dataReceived and wait until the line
            # delimiter arrives in an udp package 
            # triggering lineReceived:
            #listener.dataReceived( msg  )
            # or 2) fake a line by calling lineReceived direclty:
            listener.lineReceived( msg )

        print msg
        self.transport.write(data, (host, port))

if __name__ == '__main__':
    web = WebPushFactory()
    reactor.listenTCP(8080, web)
    reactor.listenUDP(9999, Echo(web.listeners))

    reactor.run() 

一个测试它的客户端(取自UDP client and server with Twisted Python):

#!/usr/bin/env python
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
from twisted.internet.task import LoopingCall
import sys, time

class HeartbeatSender(DatagramProtocol):
    def __init__(self, name, host, port):
        self.name = name
        self.loopObj = None
        self.host = host
        self.port = port

    def startProtocol(self):
        # Called when transport is connected
        # I am ready to send heart beats
        self.loopObj = LoopingCall(self.sendHeartBeat)
        self.loopObj.start(2, now=False)

    def stopProtocol(self):
        "Called after all transport is teared down"
        pass

    def datagramReceived(self, data, (host, port)):
        print "received %r from %s:%d" % (data, host, port)


    def sendHeartBeat(self):
        self.transport.write(self.name, (self.host, self.port))


if __name__ == '__main__':
    sender = HeartbeatSender("sender", "127.0.0.1", 9999)
    reactor.listenMulticast(9998, sender, listenMultiple=True)
    reactor.run()