2011-08-15 8 views
9

응용 프로그램 프레임 워크를 사용하여 트위스트 P2P 클라이언트를 작성하고 있습니다. 들어오는 연결의 수신 포트는 임의로 (OS가 결정한) 포트에 있습니다. 그러나, 나는 그 포트를 생성 한 후이 무엇인지 확인하는 방법이 필요합니다 : 나는 internet.TCPServer()에 의해 생성 된 포트를 쿼리에 대해 또는 reactor.listenTCP()가 전달에 의해 문서에서 아무것도 찾을 수 없습니다twisted - OS가 선택한 수신 대기 포트 받기

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) 

. 나는 클라이언트가 그 연결이 일어날 수 있도록 포트를 발표해야하기 때문에 단순히 연결이 일어날 때까지 기다릴 수 없다. 아직 서버를 시작하지 않은 경우

답변

19

listenTCPgetHost() 메서드가있는 IListeningPort 메서드를 반환합니다.이 메서드는 port의 개체를 반환합니다. 이 privilegedStartService 시작 될 때까지

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

그러나, TCPServerlistenTCP를 호출하지 않습니다 예를 들면 다음과 같습니다. 또한 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() 

당신은 다음과 같이하는 전술 파일이 사용할 수 있습니다 : 예를 들면 다음과 같습니다이다

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) 
+2

+1, 노력 : – mouad

+1

+1 주위의 가장 좋은 답변을 위해. –

0

당신과 같이 서버에 포트 바인딩에 액세스 할 수 있습니다 (아직 startService를 호출하지 않았다) : 그렇지

>>> serv._getPort()._realPortNumber 

당신은 또한 수행 할 수 있습니다

>>> serv._port._realPortNumber 
+1

이들은 비공개 API입니다. Twisted에서 "_"로 시작하는 API를 호출하지 마십시오. – Glyph

+0

@ 글리프 : OP가 문제를 지적했다. 나는 올바른 해결책이 아닌 해결책을 제시했다. 그래서 __ 내부 메서드를 호출하는 것을 포함하지 않는 또 다른 방법을 알고 있다면. __we는 모두 여기 성인입니다. – mouad

+0

내 솔루션에서 필요한 메소드를 제공합니다. 그리고 Glyphs의 논평에 관해서는 성인이 아닙니다. –

0

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

물론 이것은 엔드 포인트가 포트가있는 전송 유형을위한 경우에만 작동합니다. 예를 들어 유닉스 서버에서'PortReporter'를 사용하려고하면,'AttributeError'로 실패 할 것입니다. 이것은 명백해 보일지 모르겠지만 엔드 포인트를 사용하여 사용자가 응용 프로그램의 네트워크 구성을 완벽하게 제어 할 수 있다면 UNIX 주소를 입력 할 것인지 여부를 미리 알 수 없습니다. –

+0

감사합니다 exarkun - 확실히 하나 알고 있어야합니다. 제 경우에는 각 서비스가 HTTP로 알려져 있고 host + port 콤보를 서비스 브로커에 다시보고하는 서비스 발견 컨텍스트에서이 서비스를 사용하고 있습니다. 아직 tx 땅에서 비슷한 것을 발견하지 못했습니다. (제안 환영) – dpn

관련 문제