【Linux】Linux select多路復用socket一直返回-1(select的bug)


作者:李春港
出處:https://www.cnblogs.com/lcgbk/p/14776820.html

一、前言

最近遇到了一個很奇怪的問題,代碼邏輯是這樣:我使用Linux的socket進行TCP連接通信,客戶端在一個獨立的線程間隔5s時間不停給服務端發送心跳,服務端也會根據心跳回應。如果數據接收線程在8s內都沒有接收到任何數據,則close(socket)關閉套接字。數據接收:在數據接收線程使用了select多路復用機制,對socket是否有數據到來進行監聽。

二、問題

當關閉套接字的時候,數據接收線程發現select函數一直返回有文件描述符有數據到來,但是實際讀取socket套接字文件描述符的時候發現一直返回-1。

三、原因

這個原因我們可以通過Linux的手冊查看select的說明即可知道答案,在Linux終端使用 man select 查看,我發現一下這一段內容:

Multithreaded applications
If a file descriptor being monitored by select() is closed in another thread, the result is unspecified. On some UNIX systems, select() unblocks and returns, with an indication that the file descriptor is ready (a subsequent I/O operation will likely fail with an error, unless another the file descriptor reopened between the time select() returned and the I/O operations was performed). On Linux (and some other systems), closing the file descriptor in another thread has no effect on select(). In summary, any application that relies on a particular behavior in this scenario must be considered buggy.

譯文:

多線程應用程序
如果select()監視的文件描述符在另一個線程中被關閉,則結果是未指定的。 在某些UNIX系統上,select()解除阻塞並返回,並指示文件描述符已經就緒(后續的I/O操作可能會失敗並出現錯誤,除非在返回select()和執行I/O操作之間重新打開文件描述符)。 在Linux(和其他一些系統)上,在另一個線程中關閉文件描述符對select()沒有影響。 總之,在這個場景中,任何依賴於特定行為的應用程序都必須被認為是有bug的。

由select的手冊得知,這是select函數的一個bug,所以我們在使用select的時候需要注意。

四、解決方案

思路:

  1. 如果在select多路復用一直返回成功,但是實際讀取文件描述符數據錯誤的時候,就關閉socket,數據接收線程先不要再去監聽這個描述符;
  2. 去告訴心跳線程不要再發送心跳並且重連服務端;
  3. 心跳線程發現接收線程發過來的重連信號,則停止發送心跳並且在一定的時間間隔去重連服務端;
  4. 心跳線程重連服務端成功,告訴數據接收線程socket已經成功連接服務端,可以繼續監聽socket描述符。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM