關於在linux下epoll的使用問題

      這陣子在linux下的一個項目需要用到epoll來承受網絡的高負載,但是在使用的過程中就遇到了一些問題。

在整個過程中,我是用EPOLL 的邊緣觸發模式來實現我想要的功能。

      我是這樣實現的:在EPOLL裏面把監聽的描述符給加了進去,然後調用epoll_wait來對客戶端所連接進來的請求進行處理,假如接受到的描述符是我服務器的監聽描述符的話,那麼我就調用accept函數來得到客戶端的fd,然後把fd給添加到epoll裏面進去。假如是已經添加到epoll裏面的客戶端的fd的話,那麼我就處理它的邏輯,如此反覆。

      好了。問題就是在測試的時候就有問題了。

      當我在用模擬客戶端進行服務端訪問壓測的時候,服務端收到的信息就出錯了。具體情況是這樣的:當我對服務器進行壓測的時候,服務器是有返回的。經過幾萬次壓測之後,我把壓測軟件關掉,再用單個客戶端去登陸的時候,服務器收到的竟然是我之前進行壓測的服務器的地址,對此我很是奇怪。而且我單個客戶端也不能接受到服務器返回給我的信息(服務器確實是有返回的了,但是他接受的fd有問題,所以應該不是返回到我登陸的那個客戶端上)。後來,我發現了代碼的一個問題,就是在把我的服務器監聽客戶端連進來的那個描述符加到epoll裏面的時候,我指定的方式是邊緣觸發,也就是EPOLLET,可能是因爲這一點而導致的。於是我把這種方式給換成默認的水平觸發模式之後,一切正常。仔細分析分析,發現其原因可能是因爲邊緣觸發的不可靠引起的(相對於水平觸發),因爲邊緣觸發在使用的時候,假如一個fd連進來,服務器接受到但是沒處理其消息的情況下,它會默認你已經對fd做了你想要做的事情了。於是他的通知隊列裏面會把該fd給踢掉,然後繼續下一個,如果是在用水平觸發的時候,則情況相反,水平觸發會在你確實對該fd作出讀取操作之後,纔不會再次出現該fd,所以機制不一樣有可能導致那種問題的出現。

      隨着進一步的測試,才發現原來是在我設置監聽描述符爲非阻塞的情況下出的問題,因爲調用了錯的flag,本來應該是用F_SETFL來設置爲非阻塞的,但是我一個不小心寫成了F_SETFD來設置,用非阻塞的fd來使用ET模式,,簡直是找死。在測試的時候,經過一輪摧殘之後的服務器,在新的客戶端連接進來的時候,服務器會讀之前的fd,感覺好像是隊列一樣。慢慢排隊出來,不過這應該是使用不恰當引起的,引以爲戒了。(ps:ET模式下的epoll只能使用非阻塞noblock的描述符,而LT模式兩者即可)。問題到此就算結束了。粗心惹的禍。    

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章