L011Linux和androidNDK之socket出錯情況的處理:Interrupted system call,Try again

L011Linux和androidNDK之socket出錯情況的處理:Interrupted system call,Try again

socket一些出錯的情況,並不需要直接結束本次交互,還可以重新啓動交互,比如Interrupted system call,Try again。

Timer expired

超時,對於非阻塞的調用,超時系統有一個默認值,不同的系統有不同的設置。(可參看L009Linux和androidNDK之linux網絡通訊超時時間設置) 如果有設置的話,則使用設置的值。

Interrupted system call

我們用術語慢系統調用(slow system call)描述accept函數,該術語也適用於那些可能永遠阻塞的系統調用。永遠阻塞的系統調用有可能永遠無法返回,多數網絡支持函數都屬於這一類。舉例來說,如果沒有客戶連接到服務器上,那麼服務器的accept調用就沒有返回的保證。類似的,如果客戶端從未發送過數據,那麼read調用將永不返回。其他慢系統調用的例子是對管道和終端設備的讀和寫。一個值得注意的例外是磁盤IO,它們一般都會返回到調用者(假設沒有災難性的硬件事故)。

適用於慢系統調用的基本規則是:當阻塞於某個慢系統調用的一個進程捕獲某個信號且相應處理函數返回時,該系統調用可能返回一個EINTR錯誤。所以,我們必須對慢系統調用返回的EINTR有所準備。

爲了處理被中斷的accept,可以改成如下形式:

for (...)
{
    if((connfd=accept(listenfd,NULL, NULL)) < 0)
    {
        if (errno == EINTR)
            continue;
        else
            printf("accept error");
    }
}

這段代碼所做的事情就是自己重啓被中斷的系統調用。對於accept,以及諸如read、write、select和open之類的函數,這是適合的。不過有一個函數我們不能重啓:connect。如果該函數返回EINTR,我們就不能再次調用它,否則將立即返回一個錯誤。當connect被一個捕獲信號中斷而且不自動重啓時,我們必須調用select來等待連接完成。 (出自unix網絡編程(第三版)第五章 P115頁)

Try again

socket設置SO_RCVTIMEO和SO_SNDTIMEO對read/write的影響?看man怎麼說

SO_RCVTIMEO and SO_SNDTIMEO

Specify the receiving or sending timeouts until reporting an error. The argument is a struct timeval. If an input or output function blocks for this period of time, and data has been sent or received, the return value of that function will be the amount of data transferred; if no data has been transferred and the timeout has been reached then -1 is returned witherrno set to EAGAIN or EWOULDBLOCK, or EINPROGRESS (for connect(2)) just as if the socket was specified to be nonblocking. If the timeout is set to zero (the default) then the operation will never timeout. Timeouts only have effect for system calls that perform socket I/O (e.g., read(2), recvmsg(2), send(2), sendmsg(2)); timeouts have no effect for select(2), poll(2), epoll_wait(2), and so on.

即SO_RCVTIMEO和SO_SNDTIMEO會導致read/write函數返回EAGAIN

另外,在確定錯誤過程中,同事提到O_NODELAY會導致write接口返回EAGAIN,的確,如果設置了O_NODELAY而當前不可寫,那麼write接口會設置errno爲EAGAIN,但是write接口會返回0而不是-1.在本案中,hiredis接口中並沒有設置O_NODELAY

參考鏈接

  1. 阻塞socket上read/write出現errno爲EAGAIN的原因解密
  2. Socket編程中Interrupted system call 解釋及解決辦法
  3. L009Linux和androidNDK之linux網絡通訊超時時間設置
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章