2011-08-15 61 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返回IListeningPort,它有一個getHost()方法,該方法將port返回給對象。例如:

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

然而,直到它開始privilegedStartServiceTCPServer不叫listenTCP。另外,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) 
+2

+1,努力:) – mouad

+1

+1爲最佳答案。 –

0

您可以訪問端口綁定到你的服務器一樣,所以如果你沒有啓動服務器,但(沒有打電話startService尚):

>>> serv._getPort()._realPortNumber 

否則,你也可以這樣做:

>>> serv._port._realPortNumber 
+1

這些是私有API;請勿調用以「_」開頭的Twisted中的API。 – Glyph

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」與UNIX服務器一起使用,則它將失敗並出現「AttributeError」。這看起來很明顯,但如果你使用端點來讓你的用戶完全控制你的應用程序的網絡配置,那麼你就不會事先知道他們是否打算輸入一個UNIX地址。 –

+0

謝謝exarkun - 絕對值得注意。就我而言,我在服務發現的上下文中使用它,其中每個服務都被稱爲HTTP,並將主機+端口組合返回給服務代理。還沒有真正發現任何類似的tx土地呢..(建議歡迎) – dpn