2011-08-15 3 views
9

私は、アプリケーションフレームワークを使用してツイストP2Pクライアントを作成しています。着信接続のリスンポートは、ランダム(OSによって決まる)ポート上にあります。しかし、私はそのポートがそれを作成した後であるかを判断する方法が必要です: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) 

私はそれが転送internet.TCPServer()またはreactor.listenTCP()によって作成されたポートを照会についてのドキュメントで何かを見つけることができません。これらの接続が起こるためにクライアントがポートをアナウンスしなければならないので、単に接続が発生するのを待つことはできません。

答えて

19

listenTCPは、getHost()メソッドを持つ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はあまりしません。リスニングを開始するとすぐにポートをどこかに報告するポートレットを作成するだけです。ここでは例です:あなたはそのようにように、TACファイルでこれを使用することができます

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

@Glyph:OPは問題を述べました。私は彼に*正しい*ものではないかもしれない解決策を抱いていました。だから、__内部メソッドを呼び出すことを含まない別の方法を知っていれば、 __weはすべてここに大人です。 – mouad

+0

私のソリューションは、必要なメソッドを提供します。そして、グリフスのコメントについては大人ではありませんでした。 –

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

もちろん、エンドポイントがポートを持つトランスポートタイプの場合にのみ機能します。たとえば、UNIXサーバーで 'PortReporter'を使用しようとすると、' AttributeError'で失敗します。これは明らかかもしれませんが、エンドポイントを使用してアプリケーションのネットワーク構成を完全に制御できる場合は、UNIXアドレスを入力するかどうかを事前に知る必要はありません。 –

+0

ありがとうexarkun - 間違いなく知っている1つ。私の場合、私はサービス発見のコンテキストでそれを使用しています。ここでは、各サービスはHTTPであり、ホスト+ポートコンボをサービスブローカーに報告します。本当にtxの土地で類似したものはまだ見つかりませんでした。(提案は歓迎します) – dpn