不考慮非同步io的epoll方式的非阻塞伺服器端為了接收文件,臨時把socket設為阻塞,做法正確嗎?

詳情如下,現在伺服器在linux上用epoll方式單進程。註冊到epoll_event時每個sockfd時都會設置為非阻塞io。客戶端是安卓app,大多數服務請求是發送login或research請求,然後接收伺服器從db獲取的查詢結果,均屬於短鏈接。

現在新的需求是安卓發送圖片文件過來,伺服器必須以阻塞方式接收(能力有限並沒有考慮過非同步io)。臨時的做法就是在接收文件之前把客戶端fd改為阻塞模式,接收完成後再改回到非阻塞。
請問
1.這麼做是否正確?
2.不正確的話應該如何改進?
3.為了實現一邊傳輸文件一邊還能完成其他功能,客戶端是否必須多進程或多線程開啟多個sockfd鏈接到伺服器?

4.追問一下,如果以後需要在線聊天的功能,長鏈接和短鏈接都有的情況下,應該如何設計伺服器?(進程,線程的使用場合之類的)
有些問題估計很初級但現在邊學邊用確實沒實際經驗,尚不明白,還望賜教真誠感謝


客戶端發圖片過來的正確做法是:

1. 客戶端先使用 HTTP PUT 方式把圖片上傳到你自己的分散式文件系統,或者雲文件系統。
2. 客戶端得到剛才上傳的圖片的 URL(或者服務端事先已確定 URL告訴客戶端往那傳)
3. 客戶端把 URL 使用 TCP 發給你的 epoll 伺服器
4. 你的伺服器可以把 URL 傳遞給其他人,讓他們下載查看
5. 你的伺服器還可以後台啟動一個線程,用 HTTP 把圖片下到本地,然後跑一些處理程序,再通知你的 epoll 主線程,事先要在 epoll 裡面放一個 pipe,然後往裡面寫一個位元組,喚醒主線程。

----
HTTP PUT 是通用傳文件協議,可以支持標準的 HTTP server,可以支持斷點續傳,可以用 HTTPS加密,還可以支持各種雲伺服器,分散式文件系統,別自己寫個 TCP 來接收圖片,實在圖簡單,可以本機起一個 HTTP收文件,客戶端發好了通知下服務端,TCP服務端直接打開上傳過來的本地文件。


IO-multiplexing 必須配合 non-blocking IO。如果你用 blocking IO,那麼任何一個客戶端可以讓你的單線程伺服器失去響應,只要不發或者慢慢發數據就行了。考慮到你的客戶端是移動上網,這種情況肯定會發生。


不是很明白這個「不考慮非同步io的epoll方式」是什麼,不能為了用epoll而專門用它,沒有一系列配套的話還不如用線程池。

1. 用了事件循環而且是純單線程的話就不能改成同步,很可能直接卡住整個循環。
2. 事情做全套,多耗點時間,做一個poller,參考libzmq/epoll.cpp at master · zeromq/libzmq · GitHub,或者ring/io_loop.py at master · mar29th/ring · GitHub。
3. 這個自己決定唄。
4. 分清楚一些,聊天伺服器肯定要單獨設置,不能和API伺服器混在一起。長鏈接的話非同步I/O這一套比較適合,在硬體資源的有效利用和並發量上都比較理想,我不是很清楚有沒有更好的模式。其他的還有用UDP或者自定義協議等等。


你這些需求難道不都該用http嗎,為什麼要自己折磨自己


1. 個人認為不正確
2. 保持 nonblocking IO,上傳服務單獨做 (參考樓上大神說的
3. 是
4. 直接寫,不要慫


聽上面的話,用HTTP吧。沒特殊需要別折騰自己。

隨便一個HTTP框架都能輕鬆處理你說的問題。花一天學習,兩天嘗試,總比你瞎折騰有bug要好。


不正確。
epoll一般只有一個線程。你把其中一個socket改成阻塞的,意味著在你接收數據的時候其他所有用戶都無法發起請求。
簡單的方式是起一個新線程單獨處理文件上傳,但是這種方式局限很多,除了簡單就沒有優點了。
epoll最好是配合有限狀態機使用。epoll的事件作為觸髮狀態機的事件,用狀態機保存和處理每個socket。
如果能大改,可以考慮用協程https://zh.wikipedia.org/wiki/%E5%8D%8F%E7%A8%8B實現。


阻塞還怎麼多路?


推薦閱讀:

TAG:epoll | Linux開發 | 網路編程 | TCP |