基於epoll非同步connect實現
這幾天寫網路爬蟲, 結果伺服器長時間阻塞在connect上導致不可容忍的併發問題, 於是著手增加一個非同步connect介面.
常規的實現手段為配合select進行檢測, 不過其效能對於高併發時會有些問題, 如果想做到結構簡單合理採用one peer one thread的處理方式還會引發過多的執行緒上下文切換導致不必要的效能浪費, 故放棄使用select來實現.
由於伺服器網路庫採用epoll實現, 故此介面也基於epoll實現. 查閱了一些資料, 總結一下:
1. 設定socket為nonblocking
2. 呼叫connect
3. 將socket加入epoll監聽
4. 檢測epollout 或 epollhup, 回撥上層處理函式做相應的處理, 如果socket ready(僅檢測到epollout) 還需額外通過getsockopt判斷sock_error值是否正常
5. 將該fd從epoll中清除
ok, 流程明確後, 就開工吧.
介面需求:
1. 可以設定超時, 方便的控制時間, 精度上定為妙級即可
2. 對於連線成功, 錯誤, 超時均會回撥上層介面進行通知
資料結構和介面:
實現:
我們知道, 如果呼叫connect立刻就成功, 那麼我們也無需將其加入epoll進行等待, 這樣沒有必要, 所以, 可以稍微的優化下 :), 僅當connect的errno為EINPROGRESS時才將其加入epoll
上面, 我們成功的將處於處理中的連結加入epoll等待通知, 那麼接下來看看epoll_wait如何處理:
這裡的timeout處理的優點粗糙, 沒有使用time_wheel方式(具體方案詳見陳碩的博文 http://blog.csdn.net/Solstice/archive/2011/05/04/6395098.aspx), 而是採用的蠻力進行輪詢, 對於併發連線小時還能忍受.. 有待改進.
接下來, 我們需要處理的就是具體的事件了: 成功, 異常, 超時.
這裡簡單列舉一下成功時的處理:
這裡可以看到, 具體的回撥通知呼叫和getsockopt的檢測, so.. 至此, 便完成了非同步connect的介面.
當然, 這裡面timeout的部分還有待改進, 程式碼有些部分有些凌亂... 不過重點的在於原理配合程式碼的理解過程, 如有不正之處, 歡迎批評指出 :)