我有這樣的內存,當我們想通過套接字描述符使用select()時,應該事先將這個套接字設置爲NONBLOCKING。應該在socket被select()調用之前設置NON-BLOCKING?
但今天,我讀了一個源文件,其中似乎沒有行將套接字設置爲NON-BLOCKING 我的內存是否正確?
謝謝!
我有這樣的內存,當我們想通過套接字描述符使用select()時,應該事先將這個套接字設置爲NONBLOCKING。應該在socket被select()調用之前設置NON-BLOCKING?
但今天,我讀了一個源文件,其中似乎沒有行將套接字設置爲NON-BLOCKING 我的內存是否正確?
謝謝!
如果提供的數據多於可以裝入套接字發送緩衝區的數據,則發送()和寫入()數據塊。通常在select()編程中,除了select()之外,您不想阻塞任何地方,所以使用非阻塞模式。
對於某些Windows API,使用非阻塞模式確實非常重要。
這取決於。設置一個套接字非阻塞做幾件事情:
使沒有數據立即read()
/recv()
回報,而不是阻塞,如果沒有什麼可用的插座上閱讀。
如果您使用的是select()
,這可能不是問題。只要你只從套接字讀取select()
告訴你它是可讀的,你沒事。
使得write()
/send()
返回部分(或零)寫入,而不是阻塞,如果沒有足夠的空間在內核緩衝區中可用。
這是一個棘手。如果您的應用程序是爲了處理這種情況而編寫的,那就太好了,因爲這意味着當客戶端讀取緩慢時,您的應用程序不會阻塞。但是,這意味着您的應用程序需要將可寫數據臨時存儲在其自己的應用程序級緩衝區中,而不是直接寫入套接字,並有選擇地將套接字寫入writefds
集中。根據你的應用程序的不同,這可能是一個救星或者一個巨大的附加複雜因素。謹慎選擇。
如果在套接字連接之前設置,則會在實際建立連接之前立即返回connect()
。
類似地,如果您的應用程序需要連接到可能緩慢響應而同時繼續在其他套接字上響應的主機,則此功能有時很有用,但如果您不小心如何處理這些半連接的套接字。通常最好避免這種情況(只要在連接後將套接字設置爲非阻塞狀態(如果有的話))。
一般情況下,你不需要設置一個套接字非阻塞在select()
使用它。系統調用已經可以讓你以基本的非阻塞方式處理套接字。不過,有些應用程序需要非阻塞式寫入,而這正是該標誌仍然需要的。
通常當你使用select()時,你正在使用它是事件循環的基礎;並且在使用事件循環時,您希望事件循環僅在select()內部並且從不在其他任何地方進行阻塞。(之所以這樣,是因爲當它處理的任何套接字上有某事要做時,你的程序總是會醒來 - 例如,如果你的程序在socket A的recv()內被阻塞了,它會是無法處理來自套接字B的任何數據,直到它從套接字A獲得一些數據纔將其喚醒;反之亦然)。
因此,最好在使用select()時設置所有套接字非阻塞。這樣,您的程序就沒有機會在單個套接字上被阻塞,並且在相當長的一段時間內忽略其他套接字。
duskwuff有正確的想法時,他說
一般情況下,你不需要設置一個套接字非阻塞使用它在選擇 ()。
如果你的內核在select()方面符合POSIX標準,這是真的。不幸的是,有些人使用Linux,這是不,作爲Linux選擇()手冊頁說:
在Linux下,選擇()可能會報告套接字文件描述符爲「準備 閱讀」,而仍然一隨後的讀取塊。這可能對於 示例發生在數據已到達但檢查錯誤 校驗和時被丟棄。在其他情況下, 文件描述符被虛假地報告爲就緒。因此,在不應該阻塞的套接字上使用O_NONBLOCK可能會更安全 。
在2011年6月18日星期六左右,有關於lkml的討論。一位內核黑客試圖證明非POSIX合規性。他們在方便時尊重POSIX,當不符時褻瀆它。
他認爲「可能有兩個讀者,第二個會阻止。」但是,這樣的應用程序缺陷是不適合的。內核預計不會阻止應用程序的缺陷。內核具有明確的職責:在select()之後的第一個read()的所有情況下,內核必須返回至少1個字節,EOF或錯誤;但從不阻止。至於write(),你應該總是在寫之前測試套接字是否被select()所報告。這保證你可以寫至少一個字節,或者得到一個錯誤;但從不阻止。讓select()幫助你,不要盲目地寫,希望你不會阻止。 Linux黑客對拐角案件等的抱怨是「我們懶得解決困難問題」的委婉說法。
假設你讀取串行端口組:
分鐘N;與-icanon一起,爲已完成的讀取設置N個字符的最小值
時間N;與-icanon,組讀取的第二
分鐘250時間1
Ñ十分之超時這裏要的250個字符,或十分之一秒超時塊。當我在非阻塞模式下在Linux上嘗試這種方法時,讀取每個字符都會返回,並敲擊CPU。將其置於阻塞模式以獲取記錄的行爲是必要的。
因此,在select()方法中使用阻塞模式有很好的理由,並期望您的內核符合POSIX標準。
但是,如果您必須使用Linux,Jeremy的建議可能會幫助您應對其內核缺陷。
哇,這些答案有點混亂,兩個答案說套接字需要設置非阻塞,2答案說沒有必要。 – misteryes
@misteryes我認爲這取決於你如何嚴格定義「需要」。如果在select()指示它是read-for-read之後,只要在套接字上只調用recv()一次,則可以避免使用阻塞套接字,前提是recv()在該情況下不會阻塞。但是如果recv()無論如何阻塞(例如由於Trifle Menot的答案中描述的Linux「特性」),或者如果代碼庫中的某處後來忘記了唯一調用recv() - 一旦規則並最終調用它兩次?那麼你的程序可能會在recv()中被阻塞,可能會持續很長時間,否則會被凍結。 :( –