2014-10-02 34 views
1

我正處於遊戲場景中。服務器和客戶端都以高速率通過非阻塞UDP交換消息。理解套接字編程中的select()

(這裏可能有些奇怪......)遺留代碼也使用select()並將timeout值設置爲0,這意味着select()不會阻塞。 Select()在永久while循環內。在select()返回一個大於0的數字時,下面的代碼通過recvfrom()接收消息。如果它返回0,下面的代碼不會嘗試接收。

從打印輸出信息中,我看到select()有時返回1(大於0)。我很困惑,因爲timeout被設置爲0,select()如何有時間檢查消息是否準備好從任何readfds讀取?謝謝。

回答

1

根據the spec

成功完成後,將PSELECT()或選擇()函數應 修改的對象指向了readfds,writefds和errorfds 參數指示哪些文件描述符準備好讀取, 準備好寫入,或者有一個待處理的錯誤條件,分別爲 ,並返回所有 輸出集中就緒描述符的總數。對於每個小於nfds的文件描述符,如果在輸入時設置了 ,並且相關條件對於該文件 描述符成立,則應在成功完成時設置對應位。

如果沒有選定的描述符準備好用於請求的操作,則pselect()或select()函數應該阻塞,直到至少有一個請求的操作準備就緒,直到發生超時或者直到被信號。 timeout參數控制在超時之前pselect()或select()函數應該執行多長時間。如果超時參數不是空指針,則它指定等待選擇完成的最大時間間隔。如果指定的時間間隔沒有任何請求的操作準備就緒,則該函數應返回。如果timeout參數是一個空指針,那麼對pselect()或select()的調用將無限期地阻塞,直到至少有一個描述符符合指定的條件。 要進行輪詢,timeout參數不應該是空指針,而應該指向一個零值的timespec結構。

總之,在檢查超時之前檢查描述符。如果在調用select()時套接字已準備好數據,則超時被忽略,並且select()立即退出。

+0

謝謝。你能否解釋爲什麼他們同時使用select()和non-blocking來實現即時回報?如果select()返回0,則遺留代碼不會接收 - 在select()後立即返回;否則(select()返回1),這應該意味着已經有一些數據準備好接收了,因此可以安全地在沒有任何阻塞時間的情況下接收它們 - 在recvfrom()之後立即返回。由於兩種情況中的任何一種都能保證立即返回,爲什麼還要將套接字設置爲非阻塞?我的理解是否正確? – Nairan 2014-10-11 13:27:25

+0

從歷史上看(在Linux之前),在阻塞套接字上的'select'後面跟着'read'永遠不會阻塞,而POSIX仍然需要這個。但是Linux故意違反了POSIX,因爲Linux開發人員認爲POSIX要求「不可能實現」,儘管BSD自1980年代中期開始實施並實施。有關詳細信息,請參閱https://lkml.org/lkml/2011/6/18/76和後續信息。 – Nemo 2014-10-11 17:51:49

+0

謝謝,尼莫。 – Nairan 2014-10-15 14:56:24