不考慮非同步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實現。
阻塞還怎麼多路?
推薦閱讀: