1. 程式人生 > >linux下的select簡直太奇葩了:1024限定的不只是監聽的個數,還是檔案描述符的最大值,注意,是值

linux下的select簡直太奇葩了:1024限定的不只是監聽的個數,還是檔案描述符的最大值,注意,是值

轉自:http://m.blog.csdn.net/blog/wuzili1234/12450451

我原來自以為對select就算不熟,基本原理和使用方法也略知一二了,做了一年多的伺服器程式設計,好歹知道linux下的select不支援超過1024個的描述符,好歹知道可以通過核心編譯來重設FD_SETSIZE,也敢大言不慚地說select函式的maxfd應該是監測的所有fd值中取最大的+1,甚至連世界上有select * from的語法都知道,結果,今天直接紮紮實實栽在了select上面了:我生生花了近2個小時來跟蹤select的奇葩點。很讓人痛苦的2個小時啊,那麼多關聯點,盤根錯節揉在一塊,每條支脈都顯得那麼無辜,實在有種拔劍四顧心茫然的感覺。不過,說起來也要感謝select,要不是它,這麼讓人痛苦的2個小時不知道怎麼度過呢!總之,當我通過再三排除最終跟扯大腸一樣扯出select的各種糾結時,腦海裡不由得浮現出了一句箴言:“一切有為法,如夢幻泡影,如露亦如電,應作如是觀”。善哉。

  先說一下問題的表象,來源是這樣的:我用客戶端一次性發起超過2000個連線,等連線全部就緒後,設為非阻塞,將他們FD_SET進readset和writeset,以接收和傳送訊息。當然,這裡我還是有點上面提到的常識的,不是一下子全部FD_SET進去,而是分批次,這裡我是設成900,每次FD_ZERO之後我都設一個計數,FD_SET超過900個的socket就停止。因為每個連線做的事情很少,先發一次資料,再收一次資料就可以直接關閉,而在關閉之後就不再FD_SET相應的socket,所以理論上是可以依次處理完的。但這也是理論上,問題來了,我發現當第一批的連線(即前900個)關閉之後,後面的連線在讀資料時紛紛提示:resource temporarily unavailable。一開始我以為我沒處理好LT水平觸發,結果搞了半天沒效果,又懷疑到伺服器端寫資料時的處理,因為是邊緣觸發的,所以ET模式的EAGAIN、EWOULDBLOCK、EINTR寫法重新查了好久,還是沒有頭緒。然後開始懷疑最大檔案開啟數,只是心裡仍然覺得奇怪,因為能連續connect有2000次就已經說明不是開啟數量限制的問題了,但我仍然ulimit -n xxxx,修改什麼fs.file-max,設定Hn、sn的,syctl搞了一堆。還是搞不定。

  萬般無奈之下,突然鬼使神差般,把900改成1,就是說每次只讓它監聽一個socket上的事件,等前一個socket上的事件處理完再繼續監聽下一個socket。然後,奇葩點出現了,我打印出的輸出資訊顯示當fd=1024這個socket處理完,開始監聽值為1025的socket時,select立刻返回,並不理會我所設定的1秒的timeout超時設定。真的是1024限定的問題啊,我的第一反應是:應該是我沒設好檔案打開個數,然後我傻愣愣地重啟了虛擬機器。還是不行!這時我才開始懷疑select的第一個引數maxfd所代表的含義:沒錯啊,取所有監聽的fd的最大值然後+1,網上很多教程都是這麼寫的啊。又開始檢視FD_SET、FD_ISSE和FD_CLR的原始碼,沒看出什麼蹊蹺。網上搜select的1024限制又有一堆人說應該重新編譯linux核心,可是我只監聽一個啊,只不過這個socket的值是1025而已。還有人專門寫教程澄清說FD_SET幾個值大於1024的描述符進去是可以的,可是我的就出錯啊。

  最後,我決定放棄在linux下使用select。