最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python的Socket編程過程中實現(xiàn)UDP端口復(fù)用的實例分享

 更新時間:2016年03月19日 14:51:59   作者:liweisnake  
這篇文章主要介紹了Python的Socket編程過程中實現(xiàn)UDP端口復(fù)用的實例分享,文中作者用到了Python的twisted異步框架,需要的朋友可以參考下

關(guān)于端口復(fù)用

一個套接字不能同時綁定多個端口,如果客戶端想綁定端口號,一定要調(diào)用發(fā)送信息函數(shù)之前綁定( bind )端口,因為在發(fā)送信息函數(shù)( sendto, 或 write ),系統(tǒng)會自動給當(dāng)前網(wǎng)絡(luò)程序分配一個隨機端口號,這相當(dāng)于隨機綁定了一個端口號,這里只會分配一次,以后通信就以這個隨機端口通信,我們再綁定端口號的話,就會綁定失敗。如果我們放在發(fā)送信息函數(shù)( sendto, 或 write )之前綁定,那樣程序?qū)⒁晕覀兘壎ǖ亩丝谔柊l(fā)送信息,不會再隨機分配一個端口號。實際上,默認的情況下,如果一個網(wǎng)絡(luò)應(yīng)用程序的一個套接字 綁定了一個端口,這時候,別的套接字就無法使用這個端口。那如何讓兩個套接字都能成功綁定一個端口呢?這時候就需要要到端口復(fù)用了。端口復(fù)用允許在一個應(yīng)用程序可以把 n 個套接字綁在一個端口上而不出錯。
端口復(fù)用能在系統(tǒng)已開放的端口上進行通訊,只對輸入的信息進行字符匹配,不對網(wǎng)絡(luò)數(shù)據(jù)進行任何攔截、復(fù)制類操作,所以對網(wǎng)絡(luò)數(shù)據(jù)的傳輸性能絲毫不受影響。
但要注意,建立連接后服務(wù)端程序占用極少系統(tǒng)資源,被控端不會在系統(tǒng)性能上有任何察覺,通常被后門木馬所利用。
在winsock的實現(xiàn)中,對于服務(wù)器的綁定是可以多重綁定的,在確定多重綁定使用誰的時候,根據(jù)一條原則是誰的指定最明確則將包遞交給誰,而且沒有權(quán)限之分,也就是說低級權(quán)限的用戶是可以重綁定在高級權(quán)限如服務(wù)啟動的端口上的,這是非常重大的一個安全隱患。

Python解決UDP端口復(fù)用問題
一直覺得UDP協(xié)議很簡單,但是今天問題讓我感覺到網(wǎng)絡(luò)的基礎(chǔ)真是博大精深。

    廢話少說,來看問題吧。由于協(xié)議的需要,我得實現(xiàn)一個UDP的客戶端和服務(wù)器端,并且從同一個端口讀寫數(shù)據(jù)。

    最初不以為然,無非就是用兩個socket,一個監(jiān)聽并從這個端口讀取數(shù)據(jù)(服務(wù)器端采用了twisted),另一個向這個端口寫入數(shù)據(jù),用python實現(xiàn)只要10行左右的代碼。

def startServer(queue, port): 
  reactor.listenUDP(port, DhtResponseHandler(queue)) 
  reactor.run() 

def sendUdpMsg(self, addr, msg): 
  socketHandler = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
  socketHandler.bind(("", self.port)) 
  socketHandler.sendto(msg, addr) 
  socketHandler.close() 

     由于要向同一個端口寫數(shù)據(jù),于是client必須有bind,但是運行后發(fā)現(xiàn)server先bind了這個端口,client運行時會報錯

復(fù)制代碼 代碼如下:

error: [Errno 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted  


     一般這種錯誤時因為多個socket不能同時bind同一個地址
     由于基礎(chǔ)不夠扎實,我開始瘋狂的搜索,發(fā)現(xiàn)有人說端口復(fù)用的問題,所謂的端口復(fù)用,是指一個套接字釋放掉一個端口后有一個wait_time,另一個套接字如果接著bind就會報錯。雖然我的問題不完全一樣,但是我欣喜若狂的使用了。即在client bind前加上如下一句

socketHandler.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 

     但是仍然報錯:

復(fù)制代碼 代碼如下:

error: [Errno 10013] An attempt was made to access a socket in a way forbidden by its access permissions  


    (順便一提,還有另一個參數(shù)叫SO_REUSEPORT,即復(fù)用端口,另外有一個叫SO_EXCLUSIVEADDRUSE,即不準復(fù)用該端口,其他socket的參數(shù)還有很多,可以參考winsockhttp://msdn.microsoft.com/en-us/library/aa924071.aspx或者unix下的socket)
     這個10013錯誤讓我百思不得其解,搜索一下,主要有兩種解釋,有人說是需要提升應(yīng)用程序的權(quán)限為管理員,我用的是eclipse+pydev,提升完eclipse權(quán)限沒用,實際上還要修改python.exe的權(quán)限,方法是在這個程序上右鍵,兼容性一欄中勾上以系統(tǒng)管理員身份運行;有人說是跟其他程序地址或者端口沖突。但是我測試過發(fā)現(xiàn)都不行。

     另外,運行的時候發(fā)現(xiàn),twisted的服務(wù)器端一定是要在主線程中,否則會報signal一定要在主線程才能接受的錯誤,但是twisted的reactor一運行起來就阻塞了。

     在twisted文檔中翻到,原來還有一種UDP叫做connected UDP,變態(tài)吧,所謂connected UDP,就是只能向一個地址收發(fā)數(shù)據(jù),看起來貌似可以,但是不符合可以向多個地址接收數(shù)據(jù)。

     最后在一篇文章中翻到說需要兩個端口都設(shè)置重用,于是我試著重新寫一個服務(wù)器,與之前的客戶端配合,運行良好,完全無錯

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
sock.bind(("", port)) 
data, address = sock.recvfrom(4096) 

     好吧,看來問題在調(diào)用twisted了,不知道他是否有這樣的設(shè)置,進去將這部分代碼翻了一下,找不到這樣設(shè)置的參數(shù)。

class Port(abstract.FileHandle): 
  def __init__(self, port, proto, interface='', maxPacketSize=8192, 
         reactor=None): 
    """ 
    Initialize with a numeric port to listen on. 
    """ 
    self.port = port 
    self.protocol = proto 
    self.readBufferSize = maxPacketSize 
    self.interface = interface 
    self.setLogStr() 
    self._connectedAddr = None 
 
    abstract.FileHandle.__init__(self, reactor) 
 
    skt = socket.socket(self.addressFamily, self.socketType) 
    addrLen = _iocp.maxAddrLen(skt.fileno()) 
    self.addressBuffer = _iocp.AllocateReadBuffer(addrLen) 
    # WSARecvFrom takes an int 
    self.addressLengthBuffer = _iocp.AllocateReadBuffer( 
        struct.calcsize('i')) 
 
  def startListening(self): 
    """ 
    Create and bind my socket, and begin listening on it. 
 
    This is called on unserialization, and must be called after creating a 
    server to begin listening on the specified port. 
    """ 
    self._bindSocket() 
    self._connectToProtocol() 
 
 
  def createSocket(self): 
    return self.reactor.createSocket(self.addressFamily, self.socketType) 
 
 
  def _bindSocket(self): 
    try: 
      skt = self.createSocket() 
      skt.bind((self.interface, self.port)) 
    except socket.error, le: 
      raise error.CannotListenError, (self.interface, self.port, le) 
 
    # Make sure that if we listened on port 0, we update that to 
    # reflect what the OS actually assigned us. 
    self._realPortNumber = skt.getsockname()[1] 
 
    log.msg("%s starting on %s" % ( 
        self._getLogPrefix(self.protocol), self._realPortNumber)) 
 
    self.connected = True 
    self.socket = skt 
    self.getFileHandle = self.socket.fileno 

    難道說twisted就完全不提供這樣的功能?最終在multicast中翻到這樣一段,也就是,多播的情況是支持地址復(fù)用的,動手測起來。

class MulticastPort(MulticastMixin, Port): 
  """ 
  UDP Port that supports multicasting. 
  """ 
 
  implements(interfaces.IMulticastTransport) 
 
 
  def __init__(self, port, proto, interface='', maxPacketSize=8192, 
         reactor=None, listenMultiple=False): 
    Port.__init__(self, port, proto, interface, maxPacketSize, reactor) 
    self.listenMultiple = listenMultiple 
 
 
  def createSocket(self): 
    skt = Port.createSocket(self) 
    if self.listenMultiple: 
      skt.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
      if hasattr(socket, "SO_REUSEPORT"): 
        skt.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) 
    return skt 

     將server端改成如下代碼,運行通過!

reactor.listenMulticast(port, DhtResponseHandler(queue), listenMultiple=True) 
reactor.run() 

     感觸良多,底層的知識比較重要,浮沙筑高臺果然危險。

相關(guān)文章

  • 在?Python?中使用變量創(chuàng)建文件名的方法

    在?Python?中使用變量創(chuàng)建文件名的方法

    這篇文章主要介紹了在?Python?中使用變量創(chuàng)建文件名,格式化的字符串文字使我們能夠通過在字符串前面加上 f 來在字符串中包含表達式和變量,本文給大家詳細講解,需要的朋友可以參考下
    2023-03-03
  • Python實現(xiàn)遍歷數(shù)據(jù)庫并獲取key的值

    Python實現(xiàn)遍歷數(shù)據(jù)庫并獲取key的值

    本文給大家分享的是Python實現(xiàn)遍歷數(shù)據(jù)庫并獲取key的值的方法,主要是使用for循環(huán)來實現(xiàn),有需要的小伙伴可以參考下。
    2015-05-05
  • Python程序打包成可執(zhí)行文件exe詳解流程

    Python程序打包成可執(zhí)行文件exe詳解流程

    你是否也有希望過寫一些自己所需要的工具程序來使用,可有不想或者沒時間精力學(xué)別的語言,本篇文章教你如何將用python語言寫的程序打包成可執(zhí)行的exe文件
    2021-11-11
  • Python使用psutil獲取系統(tǒng)信息

    Python使用psutil獲取系統(tǒng)信息

    這篇文章介紹了Python使用psutil獲取系統(tǒng)信息的方法,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-05-05
  • Python實現(xiàn)K-means聚類算法并可視化生成動圖步驟詳解

    Python實現(xiàn)K-means聚類算法并可視化生成動圖步驟詳解

    這篇文章主要介紹了Python實現(xiàn)K-means聚類算法并可視化生成動圖,本文分步驟給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-05-05
  • Python計算不規(guī)則圖形面積算法實現(xiàn)解析

    Python計算不規(guī)則圖形面積算法實現(xiàn)解析

    這篇文章主要介紹了Python計算不規(guī)則圖形面積算法實現(xiàn)解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11
  • Python將Excel表格按某列拆分為多個sheet實現(xiàn)過程

    Python將Excel表格按某列拆分為多個sheet實現(xiàn)過程

    這篇文章主要為大家介紹了Python實現(xiàn)將Excel表格按某列拆分為多個sheet,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • Tensorflow的DataSet的使用詳解

    Tensorflow的DataSet的使用詳解

    本文主要介紹了Tensorflow的DataSet的使用詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • Django+Celery實現(xiàn)定時任務(wù)的示例

    Django+Celery實現(xiàn)定時任務(wù)的示例

    Celery是一個基于python開發(fā)的分布式任務(wù)隊列,而做python WEB開發(fā)最為流行的框架莫屬Django,本示例使用主要依賴包Django+Celery實現(xiàn)定時任務(wù),感興趣的朋友一起看看吧
    2021-06-06
  • 橫向?qū)Ρ确治鯬ython解析XML的四種方式

    橫向?qū)Ρ确治鯬ython解析XML的四種方式

    這篇文章主要以橫向?qū)Ρ确绞椒治鯬ython解析XML的四種方式,感興趣的小伙伴們可以參考一下
    2016-03-03

最新評論

定西市| 大港区| 石楼县| 砀山县| 金寨县| 察隅县| 凤山县| 于田县| 崇文区| 张家港市| 镇坪县| 平阳县| 萨嘎县| 广宁县| 汤原县| 公安县| 昌江| 兴义市| 房山区| 青冈县| 静宁县| 交城县| 卓资县| 扎赉特旗| 垣曲县| 涞水县| 广平县| 且末县| 长海县| 镇巴县| 邛崃市| 鹤壁市| 界首市| 朝阳区| 昭觉县| 巩义市| 图片| 都江堰市| 宁津县| 深泽县| 祁东县|