2013-12-09 42 views
7

我正在使用Python編寫一個面向網絡的應用程序。我以前曾使用過阻塞套接字,但是在更好地理解了需求和概念之後,我想使用非阻塞套接字編寫應用程序,從而使用事件驅動的服務器。Python的select模塊中的select()函數如何正確工作?

我知道Python中select模塊中的函數可以用來方便地查看哪些套接字感興趣,等等。爲實現這一目標,我基本上是試圖通過幾個事件驅動服務器的例子,翻轉和我曾經碰到過這樣一句:

""" 
An echo server that uses select to handle multiple clients at a time. 
Entering any line of input at the terminal will exit the server. 
""" 

import select 
import socket 
import sys 

host = '' 
port = 50000 
backlog = 5 
size = 1024 
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
server.bind((host,port)) 
server.listen(backlog) 
input = [server,sys.stdin] 
running = 1 
while running: 
    inputready,outputready,exceptready = select.select(input,[],[]) 

    for s in inputready: 

     if s == server: 
      # handle the server socket 
      client, address = server.accept() 
      input.append(client) 

     elif s == sys.stdin: 
      # handle standard input 
      junk = sys.stdin.readline() 
      running = 0 

     else: 
      # handle all other sockets 
      data = s.recv(size) 
      if data: 
       s.send(data) 
      else: 
       s.close() 
       input.remove(s) 
server.close() 

,我似乎沒有明白的部分如下:

在代碼片段inputready,outputready,exceptready = select.select(input,[],[])中,我相信select()函數返回三個可能爲空的輸入,輸出和異常條件對象的空列表。所以有意義的是select()函數的第一個參數是包含服務器套接字和stdin的列表。但是,我所面臨的困惑是在else代碼塊中。

由於我們正在循環使用已輸入套接字的列表,因此顯然select()函數將選擇一個準備好讀取的客戶機套接字。但是,在我們使用recv()讀取數據並發現套接字實際上已發送數據之後,我們希望將其回顯給客戶端。我的問題是我們如何寫入這個套接字而不將它添加到作爲select()函數調用的第二個參數傳遞的列表中?也就是說,我們如何直接在新套接字上調用send(),而不用將其註冊爲select()作爲可寫套接字?

此外,爲什麼我們只能通過套接字準備好讀取(在這種情況下輸入已準備好)?是否有必要遍歷輸出結果列表以查看哪些套接字已準備好寫入? 顯然,我在這裏失去了一些東西。

如果有人能夠以更詳細的方式解釋功能的工作或指向良好的文檔,這也將非常有幫助。

謝謝。

+2

我覺得你被樣本代碼的細節混淆。調用發送套接字而不等待它準備好寫入就沒有問題,但是如果輸出緩衝區已滿,就會阻塞。他們在示例代碼中忽略了這種情況。你可能想查看'select'手冊頁,因爲這是一個很薄的包裝器。我假設你已經找到http://docs.python.org/2/library/select.html –

回答

1

也許這段代碼只是一個簡單的例子,所以它不是詳盡的。如果select沒有告訴你它們已經準備好,你可以自由地在每個套接字中編寫和讀取。但是,當然,如果你這樣做,你不能確定你的send()不會被阻塞。 所以,是的,最好的做法是依靠選擇來進行書寫操作。 也有許多其他功能具有相似的目的,在許多情況下,它們都比選擇更好(例如epoll),但它們不適用於所有平臺。 有關選擇,epoll &其他功能的信息可以在Linux手冊頁找到。

然而在Python有用來處理許多連接許多不錯的圖書館,其中的一些是:Twistedgevent

+0

謝謝@Faust。在沒有Twisted之類的幫助下編寫應用程序是否是一項艱鉅的任務? – gravetii

+1

這取決於你的需求。例如像gevent這樣的lib可以選擇當前平臺上可用的最佳工具(即Linux上的epoll和FreeBSD上的kqueue)。你可以自己做,但如果你的項目不僅僅是一個實驗,而且你真的需要最好的性能,可能最好依賴廣泛使用和測試的工具,比如gevent或Twisted。 達到這些庫的優化水平並不容易。 – smeso