2012-12-07 43 views
6
open_sockets = [] 

listening_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 

listening_socket.bind(("", 1234)) 

listening_socket.listen(5) 

while True: 
    rlist, wlist, xlist = select.select([listening_socket] + open_sockets, [], []) 
    for i in rlist: 
     if i is listening_socket: 
      new_socket, addr = listening_socket.accept() 
      open_sockets.append(new_socket) 
     else: 
      data = i.recv(1024) 
      if data == "": 
       i.close() 
       open_sockets.remove(i) 
       print "Connection closed" 
      else: 
       i.send(data) 
       print repr(data) 

現在我知道這是簡單的服務器代碼,可以處理一些客戶 - 我不明白的唯一事情是這兩行:的recv()在Python

 data = i.recv(1024) 
     if data == "": 

我明白當客戶端已經接受它時會轉到另一個選項,該選項檢查緩衝區中是否存在某些內容。我不明白爲什麼,當沒有什麼緩衝區,如此下去,不檢查線路:

if data == "": 

但是當客戶只需按下回車鍵,相當於""它斷開

爲什麼在沒有任何東西被按下時它不是和""一樣?

+0

要如果提供的答案中的任何一個回答了您的問題,請務必接受答案。這是一個很好的方式來感謝對本網站有貢獻的人們。如果您的問題未得到解答,請隨時發表評論。謝謝! – GargantuChet

回答

6

它從select呼叫開始。該功能監視套接字並等待值得注意的事情發生。對於第一個列表中的套接字,「值得注意」意味着套接字具有可供讀取的數據。

rlist, wlist, xlist = select.select([listening_socket] + open_sockets, [], []) 

代碼現在通過插座與基於套接字類型準備讀取數據,以及行爲的列表上循環被處理。

for i in rlist: 
     if i is listening_socket: 

面向連接(「偵聽」)套接字用於接受新的連接。由於它在rlist,我們知道它有一些東西供我們「閱讀」。在偵聽套接字的上下文中,這意味着已經收到新的連接。因此,我們接受連接,並將新套接字保存在open_sockets的列表中。

  new_socket, addr = listening_socket.accept() 
      open_sockets.append(new_socket) 

如果套接字不listening_socket,那麼它是一個插座,它是(或者是),連接到遠程客戶端。再次,因爲它在rlist,我們知道它有一些東西讓我們「閱讀」。在連接套接字的情況下,這意味着數據實際上可以被讀取,或者套接字已經關閉。

所以我們稱之爲recv得到任何可用的數據,

 else: 
      data = i.recv(1024) 

,看看我們實際上讀什麼。如果沒有數據可用,則連接必須已關閉,因此我們關閉套接字對象並將其從open_sockets中刪除。

  if data == "": 
       i.close() 
       open_sockets.remove(i) 
       print "Connection closed" 

如果我們確實收到數據,我們只是將它寫回客戶端並將其打印在屏幕上。

  else: 
       i.send(data) 
       print repr(data) 

select的第一個電話將等待,直到收到連接。您可以通過更新代碼

print "About to call select" 
rlist, wlist, xlist = select.select([listening_socket] + open_sockets, [], []) 
print "Returned from select" 

看到自己第一個電話後,rlist將包括listening_socket。我們知道這是因爲open_sockets是空的,並且在被讀取爲「讀取」之前,所謂的select將不會返回。所以我們接受新的連接並將其添加到open_sockets

select被再次調用,有三種可能的事件。首先,listening_socket可能已經收到另一個連接。在這種情況下,它的處理方式與之前一樣:我們接受連接並將其添加到open_sockets

其次,新的連接可能接收到的數據。由於select包含在rlist中,所以我們知道有數據準備從套接字「讀取」(意味着數據已準備好讀取,或套接字已關閉)。 i.recv將返回新的數據。

第三,新的連接可能已被關閉。由於select包含在rlist中,我們知道有數據可以從套接字讀取(具有與上述相同的含義)。但是i.recv將返回「」,因爲套接字沒有任何新數據。所以我們知道套接字已經關閉,並相應地清理。

如果沒有數據從客戶端發送(並且連接仍處於打開狀態),則select將不包含在rlist中。所以循環將不會處理它,並且i.recv將不會在該特定的套接字上調用。

+0

這裏值得一提的是'socket.setblocking()'和'socket.settimeout()'在這裏我認爲,因爲'recv'將不會被普遍地阻止。 –

+0

它不會阻止。 '我在rlist'上說'我'已經準備好閱讀了。 1024 BUFSIZE則recv()可以返回understand.what你說的是,如果按沒有它不會傳球線路,所以它會被卡住並不會得到通過對其他客戶或你的意思是,它會更少字節 – jfs

+0

我沒有退出跳過if條件? – user1779374

3

當套接字發送""作爲響應時,通常意味着套接字已關閉(或關閉?)。有人糾正我,如果我在這裏錯了。沒有這個聲明,如果遠程服務器突然停止響應,它可能陷入無限循環。

+0

這是正確的。這只是發生在我身上,它造成了巨大的內存過載bc我正在追加數據到列表中查找終端標記。感謝您指出了這一點。 –

+0

@MichaelDavidWatson一個相當流行的網絡庫有一個類似的錯誤,並導致令人困惑的無限循環掛起在我的代碼。一個簡單的「如果不是數據:引發異常」通常是最好的解決方案。 – Anorov

0

i(順便說一句,對於插座一個不幸的名稱)將不會在rlist除非有東西可以讀即i.recv(1024)將返回東西或連接完成後,即i.recv(1024)回報b""

一旦.recv()回到b""您將不會收到來自這個插座什麼。

的「客戶端(人)只是按下回車」取決於客戶端(軟件)的解釋。它沒有任何與服務器如做,客戶端可以緩衝輸入字符串,直到一個換行符遇到或超時發生,也可以儘快收到它從用戶發送的每個字節等

-1
[[email protected] ]# grep "banner_timeout = " /opt/panel-migrator/thirdparties/python/lib/python2.7/site-packages/paramiko/transport.py 

self.banner_timeout = 60  # how long (seconds) to wait for the SSH banner