twisted - получить выбранный ОС порт прослушивания - PullRequest
9 голосов
/ 15 августа 2011

Я пишу скрученный P2P-клиент, используя платформу приложения. Порт прослушивания для входящих подключений будет на случайном (определяемом ОС) порту. Однако мне нужен способ определить, что это за порт после его создания:

import twisted... etc.

application = service.Application('vmesh')
peerservice = MyPeerService()
servicecollection = service.IServiceCollection(application)
factory = MyPeerFactory(peerservice)
server = internet.TCPServer(0, factory) # listen on random port
listen_port = server.getHost().port # ??? doesn't work...
server.setServiceParent(servicecollection)

Я не могу найти в документации ничего о запросе порта, созданного internet.TCPServer() или reactor.listenTCP(), на который он пересылается. Я не могу просто ждать, пока произойдет соединение, так как клиент должен объявить свой порт, чтобы эти соединения когда-либо происходили.

Ответы [ 3 ]

20 голосов
/ 16 августа 2011

listenTCP возвращает IListeningPort, который имеет метод getHost(), который возвращает объект с port. Например:

>>> from twisted.internet import reactor
>>> from twisted.internet.protocol import Factory
>>> port = reactor.listenTCP(0, Factory())
>>> port.getHost().port
55791

Тем не менее, TCPServer не вызывает listenTCP, пока не будет запущено с privilegedStartService. Кроме того, IListeningPort на самом деле не доступен через публичный API. Итак, вам нужно написать свой Service. К счастью, это довольно легко сделать; TCPServer не очень много делает. Вам просто нужно написать тот, который сообщит свой порт куда-нибудь, как только он начнет слушать. Вот пример:

from twisted.internet import reactor
from twisted.application.service import Service

class PortReporter(Service, object):
    def __init__(self, factory, reportPort):
        self.factory = factory
        self.reportPort = reportPort

    def privilegedStartService(self):
        self.listeningPort = reactor.listenTCP(0, self.factory)
        self.reportPort(self.listeningPort.getHost().port)
        return super(PortReporter, self).privilegedStartService()

    def stopService(self):
        self.listeningPort.stopListening()
        return super(PortReporter, self).stopService()

Затем вы можете использовать это в файле TAC, например:

from twisted.internet.protocol import Factory
from twisted.application.service import Application
application = Application("test")
def showPortNumber(n):
    print("The port number is: %d" % (n,))
PortReporter(Factory(), showPortNumber).setServiceParent(application)
0 голосов
/ 03 июля 2014

FWIW, если вам нужно сделать это с конечными точками, здесь моя реализация с небольшим изменением моей локальной настройки (опция обратного вызова тоже подойдет):

class PortReporter(StreamServerEndpointService, object):
    def __init__(self, endpoint, factory):
        StreamServerEndpointService.__init__(self, endpoint, factory)
    self._reportedPort = None

def privilegedStartService(self):
    r = super(PortReporter, self).privilegedStartService()
    self._waitingForPort.addCallback(self.port_cb)
    return r

def port_cb(self, port):
    self._reportedPort = port.getHost().port
    return port

def getReportedPort(self):
    return self._reportedPort
0 голосов
/ 16 августа 2011

Вы можете получить доступ к привязке порта к вашему серверу, например, если вы еще не запустили сервер (еще не вызывали startService ):

>>> serv._getPort()._realPortNumber

Иначе вы можететакже сделать:

>>> serv._port._realPortNumber
...