在使用Multiplexed I/O的情況下,還有必要使用Non Blocking I/O么 ?
今天在看別人寫的一段server代碼的時候發現,他在使用select的情況下,仍然把註冊到select里的file descriptor設置成了nonblocking。但是我的理解是,如果使用select的話,只會對ready的file descriptor操作,不會block啊。是我的理解有問題,還是他寫的有問題?
題主的理解有問題。可以思考個簡單的例子:
如果某個socket描述符返回可寫,說明該描述符的發送緩衝區可用位元組數高於低水位。那假設發送緩衝區低水位為100,目前發送緩衝區有1000Bytes的可用空間,如果你需要發2000Bytes的數據,如果socket是非阻塞的,發送完1000Bytes到發送緩衝區之後會立刻返回,等下次緩衝區可寫時繼續寫;如果socket是阻塞的,發送完了1000Bytes到發送緩衝區,線程就阻塞了。另外一個例子,前面陳碩的答案提到了Linux Programmer "s Manual,select的手冊有如下內容:
Under Linux, select() may report a socket file descriptor as "ready for reading", while nevertheless a subsequent read blocks. This could for example happen when data has arrived but upon examination has wrong checksum and is discarded. There may be other circumstances in which a file descriptor is spuriously reported as ready. Thus it may be safer to use O_NONBLOCK on sockets that should not block.
當某個socket接收緩衝區有新數據分節到達,然後select報告這個socket描述符可讀,但隨後,協議棧檢查到這個新分節檢驗和錯誤,然後丟棄這個分節,這時候調用read則無數據可讀,如果socket沒有被設置nonblocking,此read將阻塞當前線程。
可以看出,select返回某個描述符讀寫就緒,並不意味著接下來的讀寫操作全過程就一定不會阻塞。所以I/O多路復用絕大部分時候是和非阻塞的socket聯合使用。你的理解有問題,去看 man select.
水平觸發的可以是block的,邊緣觸發的必須是nonblock。select只支持水平觸發是可以block模式的,也可以 nonblock的。最好是nonblock模式吧,極端情況下select,poll返回不一定真的可讀寫,而且write是會阻塞的。
select又不能把阻塞變成非阻塞,這兩個不是一碼事
是對Ready的Socket沒錯,但是它的Ready是指一旦有數據就Ready,就被select選中,然後讀。但沒讀到你要求的數據量的時候就會停在那。也就是堵在讀某個具體的Socket上,你用select來選擇讀哪個Socket的目的就達不到了。
select是幫你對1-1024個文件描述符一個個去試,如果哪個可以讀了,就告訴你,這裡有可以讀的文件描述符了。然而如果是阻塞式的io,你在試的時候已經阻塞住了,還哪有什麼一個個試呢。非阻塞的io才能說我試一下,得到成功或者不成功。
推薦閱讀:
※超級計算機的組成:一個系統還是多個系統協同合作?
※Linux 作為伺服器操作系統的優勢是什麼?
※符號連接、軟連接、硬連接、快捷方式、副本(copy)之間有何區別和聯繫?
※為什麼現在的Windows中不能在硬碟分區的根目錄下建立名為$bitmap的文件?
※你們見過的最快的開機速度是多少秒?