TCP超時設置


  在學習TCP超時設置的時候,發現網上沒有完整的超時介紹,遂總結一下。TCP超時總共分為3類:connectTimeout, writeTimeout, readTimeout(連接超時,讀超時,寫超時)。下面分別介紹如何設置這三種超時。

1. 連接超時

  在TCP調用connect函數時,TCP的建立需要3次握手,從客戶端發出SYS信號之后開始等待,超過超時時間即連接失敗,connect函數不再等待,直接返回。這個時間稱為超時時間。超時時間系統是有最大限制的,以Linux系統為例,調用命令:sysctl net.ipv4.tcp_syn_retries可以查看系統設置的connectTimeout最大值。返回值:

4:timeout是31s

5: timeout是75s

6: timeout是127s

但是有時我們希望設置自己的connectTimeout時間(注:此時間必須比系統timeout時間短,否則系統會截成系統timeout時間)。

1.1 使用alarm函數

在設置超時時間時,可以采用alarm函數,具體如下:

//超時處理函數
void alarm_handler(int sig)
{
    printf("connect timeout");
    return;
}

int main()
{
    ...
    signal(SIGALRM, alarm_handler)
    alarm(5); //設置超時時間5s
    int rc=connect(...); //調用connect函數
    alarm(0);
    if(rc<0){
        if(errno==EINTR){
            //connect超時
      }
    }
}

這種方法可能有以下缺陷:

(1) 有些UNIX操作系統在信號處理程序返回之后可能重啟connect調用;

(2) 假如connect成功,但是此時alarm定時到了,此時程序仍然會終止。

1.2 使用select函數

使用select函數,監聽套接字是否有讀或寫性質的變化(實際上監視寫性質的變化就行了,因為一旦連接成功,套接字一定是可寫的)。下面看偽代碼:

 1 int main()
 2 {
 3     int sock; 
 4     
 5     sock=socket(AF_INET,SOCK_STREAM,0); //1.調用socket函數
 6     
 7     //2. 將sock設置成非阻塞
 8     
 9     //3.調用connect函數
10     int rc=connect(sock,...); 
11     /*****************
12     調用connect函數后,因為設置成非阻塞,會有三種典型情況:
13     1. rc=0,連接成功
14     2. rc!=0 && errno=EINPROCRESS,說明還未連接成功
15     3. rc!0 && errno=!EINPROCRESS,連接失敗
16     ******************/
17     if(rc==0){
18         連接成功,將sock設置成阻塞;
19         執行后續客戶端程序;
20     }
21     else if(rc!=0 && error!=EINPROCRESS)
22         連接失敗,直接返回;
23     else{
24         fd_set rdevent,wrevent,exevent; //這里可以只檢測寫事件,即wrevent
25         FD_ZERO(&rdevent);
26         FD_SET(sock,&rdevent);
27         wr=rdevent;
28         exevent=rdevent;  //設置讀監視,寫監視以及異常監視
29         tv.tv_sec=5;
30         tv.tv_usecc=0; //設置超時時間5s,此部分相關操作均可在select函數使用方法中查詢
31         rc=select(sock+1,&rdevent,&wrevent,&exevent,&tv);
32         if(rc<0)
33             select函數錯誤;
34         else if(rc==0)
35             select函數超時,即連接超時connectTimeout
36         else{   //有監測信號返回
37             //此時檢測是否是連接成功
38             if(!FD_ISSET(sock,&rdevent) && !FD_ISSET(sock,&wrevent))  //既不可讀,也不可寫,一定是連接錯誤
39             int err;
40             int len=sizeof(err);
41             if(getsockopt(sock,SOL_SOCKET,SO_ERROR,&err,&len)<0)
42                 調用getsockopt()函數本身的錯誤;
43             if(err!=0) 
44                 說明連接錯誤,退出;
45             else
46                 連接成功,設置sock為阻塞,開始客戶端處理函數;
47         }
48     }
49 }

  最關鍵的判斷有兩處,一是調用connect()函數后有三種可能情況,見上面12-15行;二是slelect檢測到了性質變化,調用getsockopt()函數,如果返回的錯誤err=0,說明沒錯,連接建立,否則連接沒建立,見上面41-46行。

注:若conenct函數調用失敗之后,不能馬上再次調用connect函數,必須先關閉套接字。

 

2. writeTimeout和readTimeout超時

讀寫超時設置要用到函數setsockopt(),這個比較簡單,直接在客戶端設置一下就可以了,如下:

tv.tv_sec=3;
tv.tv_usec=0;
setsockopt(sock,SOL_SOCKET,SO_SNDTIMEO,&tv,sizeof(tv));
setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv));

 


免責聲明!

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



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