網路程式設計中的超時檢測

wzm10455發表於2013-04-20

http://www.embedu.org/Column/Column208.htm


作者:曾巨集安,華清遠見嵌入式學院講師。

我們在網路程式設計中常見的一種做法是:建立好套接字後以阻塞的方式讀寫,如果沒有資料可讀的話,程式會一直等待。事實上,網路狀況一直不斷變化,很有可能在通訊過程中出現網路連線斷開。我們在程式中有必要對這種情況進行檢測,從而及時做出響應。下面介紹幾種常用的超時檢測方法(假設我們要求通過套接字等待資料的最大時間為8秒):

一、 設定套接字接收超時

setsockopt可以設定套接字的屬性,其中包括接收超時時間。參考程式碼如下
        struct timeval tv; // 描述時間的結構體變數
        ……
        tv.tv_sec = 8;
        tv.tv_usec = 0;
        setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
        ……

二、 多路IO複用select

select 函式通常被用來實現多路IO複用,同樣可以利用它來實現超時處理。參考程式碼如下:
        struct timeval tv; // 描述時間的結構體變數
        fdset rdfds; // 定義讀描述符集合
        ……
        tv.tv_sec = 8;
        tv.tv_usec = 0;
        FD_ZERO(&rdfds);
        FD_SET(sockfd, &rdfds);
        if (select(sockfd+1, &rdfds, NULL, NULL, &tv) == 0)
        {
                超時處理
        }
        ……

三、 設定定時器

這種方法的原理是在從套接字接收資料之前先設定8秒鐘的定時器。如果8秒鐘內沒有資料到來,核心產生的SIGALRM訊號會中斷當前的讀操作。我們知道設定訊號捕捉函式可以用signal函式或是sigaction函式。但這裡只能使用sigaction函式,因為signal設定的訊號處理函式執行完後會重新執行被中斷的操作。參考程式碼如下:

void handler(int signo) // 自定義SIGALRM訊號處理函式
        {
                return;
        }
        struct sigaction act; // 描述訊號行為的變數
        ……
        sigaction(SIGALRM, NULL, &act); // 獲取SIGALRM訊號的屬性
        act.sa_handler = handler; // 設定SIGALRM訊號的處理函式
        act.sa_flags &= ~SA_RESTART; // 關閉重啟被中斷操作的選項
        sigaction(SIGALRM, &act, NULL); // 設定SIGALRM訊號的屬性
        alarm(8); // 設定8秒鐘的定時器
        ……

雖然我們是以套接字的讀操作為例,實際上在很多類似的情況中,大家都可以酌情采取上面介紹的方法。巧妙的運用所學知識會讓你的程式更加靈活和人性化。

相關文章