1. 程式人生 > >為什麽IO多路復用需要采用非阻塞式IO

為什麽IO多路復用需要采用非阻塞式IO

data linux 當前 sock blocks linux內核 report 知乎 只有一個

近段時間開始學習《Unix網絡編程》,代碼實現了一個簡單的IO多路復用+阻塞式的服務端,在學習了非阻塞式IO後,有一個疑問,即:

假如調用了select,並且關註了幾個描述字,當關註的描述字可讀時,select成果返回並告訴我對應套接口已可讀,此時采用阻塞式read或非阻塞式read去讀套接口有何區別,既然已經告訴套接字可讀,調用read怎麽還會發生阻塞。即本問題,為什麽IO多路復用需要采用非阻塞式IO。

當時理解不深,不知道該問題存在原因,第二天偶然刷知乎,刷到了這個問題。現解釋如下:

1、首先看下man 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可能存在如下問題:當新數據到達描述符,select返回描述符可讀,但Linux內核協議棧檢查到新數據包的校驗和錯誤,故丟棄該數據,采用阻塞式IO去讀該套接口,無數據可讀,則當前進程阻塞。 2、第二種解釋有: 一種典型場景,驚群現象:當采用多線程方式通過select或epoll監聽套接字,當新連接到達,則所有監聽套接字的線程會通過select被喚醒,但是最終只有一個線程會通過accept與這個新連接建立握手關系,如果采用了阻塞式IO,則其余所有沒有接收到accept連接的線程會阻塞。

為什麽IO多路復用需要采用非阻塞式IO