2016-08-26 36 views
0

我在這裏是一個noob,但試圖設置一個腳本,我可以輪詢一個套接字,並且當沒有套接字數據發送時,循環繼續運行並執行其他操作。我一直在玩使用select()發現的幾個例子,但不管我如何組織代碼,它似乎停止在server.recv()行上或附近,並等待響應。如果客戶端沒有發送數據,或者沒有客戶端連接,我想跳過這一點。Python套接字選擇正在掛起 - 在等待套接字數據時執行其他任務?

請注意,此應用程序不需要服務器腳本發送任何答覆數據,如果它有任何區別。

實際應用是運行一個循環併爲一些LED設置動畫(需要根訪問Raspberry Pi上的I/O)。我將通過套接字從另一個單獨的腳本發送此腳本數據,這些套接字將傳遞動畫的控制參數。這樣外部腳本不需要root權限。

到目前爲止,數據的發送和接收都非常有效,我無法在沒有輸入數據的情況下獲得循環。這是我的理解,這是select()打算允許的,但我發現的例子似乎並沒有這樣工作。

我試圖添加server.setblocking(0)幾個不同的地方無濟於事。 (如果我理解正確,一個非阻塞實例應該允許代碼跳過recv(),如果沒有數據已經​​發送,但我可能會關閉)。

我有我的基礎上這裏的示例代碼: http://ilab.cs.byu.edu/python/select/echoserver.html

這裏是服務器端腳本,然後客戶端腳本。

服務器代碼:sockselectserver.py

#!/usr/bin/env python 

import select 
import socket 
import sys 

server = socket.socket() 
host = socket.gethostname() 
port = 20568 
size = 1024 
server.bind((host,port)) 
server.listen(5) 
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) 
    print "looping" 
server.close() 

客戶端代碼:skclient.py

#!/usr/bin/python   # This is client.py file 

import socket    # Import socket module 

s = socket.socket()   # Create a socket object 
host = socket.gethostname() # Get local machine name 
port = 20568    # Reserve a port for your service. 

s.connect((host, port)) 

data = "123:120:230:51:210:120:55:12:35:24" 
s.send(data) 
print s.recv(1024) 
s.close      # Close the socket when done 

我想什麼通過這個例子來實現,就是看 「循環」 重複永遠,然後當客戶端腳本發送數據時,看到數據打印,然後一遍又一遍地看到「循環」恢復打印。那會告訴我它正在做我打算從那裏拿到的東西。

有趣的是,當我按照原樣進行測試時,無論何時運行客戶端,我都會在屏幕上看到「循環」打印3次,然後就不再顯示了。我不完全理解選擇內部發生了什麼,但我認爲它只會打印一次。

我試着將inputready .. select.select()移動到不同的地方,但發現它似乎需要每次調用,否則服務器停止響應(例如,如果它在無盡的while :循環)。

我希望這可以做得很簡單,它可以教授製造商類的其他黑客類型,所以我希望我不需要太多瘋狂的多線程和更復雜的解決方案。作爲最後的手段,我正考慮從外部腳本中將所有參數記錄到mySQL,然後使用此腳本將它們從表格中查詢回來。我有經驗,可能會工作,但似乎這個插座角度將是一個更直接的解決方案。

任何幫助,非常感謝。

+0

服務器必須是它​​自己的循環imo – YOU

+0

感謝您的快速回復。我不知道我將如何實現這一點。你能分享一個示例代碼片段嗎?我是否將所有內容都封裝在一個循環中?如果是,我會在哪裏調用其他函數(那些將被反覆調用的函數,僅在客戶端發送傳入數據時纔會中斷)? – kjav

+0

嘗試使用超時(秒)調用'select.select()'選項:'select.select(input,[],[],1)'。 – acw1668

回答

0

好消息。這是一個簡單的解決方案,想要發佈以防其他人需要它。上面的acw1668的建議讓我走了。

簡單相加的「0」超時到select.select()這樣的:

inputready,outputready,exceptready = select.select(input,[],[],0) 

這是Python文檔,但不知何故我錯過了。鏈接在這裏:https://docs.python.org/2/library/select.html

每文檔: 「可選的超時參數指定超時以秒爲一個浮點數當超時參數被忽略的功能塊,直到至少一個文件描述符準備好。超時值零指定一個輪詢並且永不阻塞。「

我測試了與上面相同的代碼,在打印「循環」行之後使用time.sleep(5)添加了5秒的延遲。延遲時間,如果沒有數據或客戶端存在,則代碼每5秒循環一次並打印「循環」到屏幕。如果我在5秒延遲期間啓動客戶端腳本,它將暫停,並在下一次5秒延遲結束時處理消息。偶爾它不響應下一個循環,而是響應下一個循環。我認爲這是因爲第一次通過server.accept正在運行,並且下一次通過s.recv()正在運行實際交換數據。