Linux下Socket連線逾時的一種實現方法

來源:互聯網
上載者:User

目前各平台通用的設定通訊端(Socket)連線逾時的辦法是:

  1. 建立通訊端,將其設定成非阻塞狀態。
  2. 調用connect串連對端主機,如果失敗,判斷當時的errno是否為EINPROGRESS,也就是說是不是串連進行中中,如果是,轉到步驟3,如果不是,返回錯誤。
  3. 用select在指定的逾時時間內監聽通訊端的寫就緒事件,如果select有監聽到,證明串連成功,否則串連失敗。

  以下是Linux環境下的範例程式碼:

#include <stdlib.h><br />#include <stdio.h><br />#include <unistd.h><br />#include <fcntl.h><br />#include <sys/types.h><br />#include <sys/socket.h><br />#include <netinet/in.h><br />#include <errno.h><br />#include <time.h><br />int main(int argc, char *argv[])<br />{<br /> int fd, retval;<br /> struct sockaddr_in addr;<br /> struct timeval timeo = {3, 0};<br /> socklen_t len = sizeof(timeo);<br /> fd_set set;<br /> fd = socket(AF_INET, SOCK_STREAM, 0);<br /> if (argc == 4)<br /> timeo.tv_sec = atoi(argv[3]);<br /> fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);<br /> addr.sin_family = AF_INET;<br /> addr.sin_addr.s_addr = inet_addr(argv[1]);<br /> addr.sin_port = htons(atoi(argv[2]));<br /> printf("%d/n", time(NULL));<br /> if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {<br /> printf("connected/n");<br /> return 0;<br /> }<br /> if (errno != EINPROGRESS) {<br /> perror("connect");<br /> return -1;<br /> }<br /> FD_ZERO(&set);<br /> FD_SET(fd, &set);<br /> retval = select(fd + 1, NULL, &set, NULL, &timeo);<br /> if (retval == -1) {<br /> perror("select");<br /> return -1;<br /> } else if(retval == 0) {<br /> fprintf(stderr, "timeout/n");<br /> printf("%d/n", time(NULL));<br /> return 0;<br /> }<br /> printf("connected/n");<br /> return 0;<br />}

 

實際運行結果如下:

xiaosuo@gentux perl $ ./a.out 10.16.101.1 90<br />1180289276<br />timeout<br />1180289279<br />xiaosuo@gentux perl $ ./a.out 10.16.101.1 90 1<br />1180289281<br />timeout<br />1180289282

 

可以看到,以上代碼工作的很好,並且如果你想知道串連發生錯誤時的確切資訊的話,你可以用getsocketopt獲得:

int error;<br />socklen_t errorlen = sizeof(error);<br />getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &errorlen);

 

但是多少有些複雜,如果有象SO_SNDTIMO/SO_RCVTIMO一樣的通訊端參數可以讓逾時操作跳過select的話,世界將變得更美好。當然你還可以選用象apr一樣提供了簡單介面的庫,但我這裡要提的是另一種方法。

  呵呵,引子似乎太長了點兒。讀Linux核心源碼的時候偶然發現其connect的逾時參數竟然和用SO_SNDTIMO操作的參數一致:

  File: net/ipv4/af_inet.c

559 timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);<br /> 560<br /> 561 if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {<br /> 562 /* Error code is set above */<br /> 563 if (!timeo || !inet_wait_for_connect(sk, timeo))<br /> 564 goto out;<br /> 565<br /> 566 err = sock_intr_errno(timeo);<br /> 567 if (signal_pending(current))<br /> 568 goto out;<br /> 569 }

 

    這意味著:在Linux平台下,可以通過在connect之前設定SO_SNDTIMO來達到控制連線逾時的目的。簡單的寫了份測試代碼:

#include <stdlib.h><br />#include <stdio.h><br />#include <sys/types.h><br />#include <sys/socket.h><br />#include <netinet/in.h><br />#include <errno.h><br />int main(int argc, char *argv[])<br />{<br /> int fd;<br /> struct sockaddr_in addr;<br /> struct timeval timeo = {3, 0};<br /> socklen_t len = sizeof(timeo);<br /> fd = socket(AF_INET, SOCK_STREAM, 0);<br /> if (argc == 4)<br /> timeo.tv_sec = atoi(argv[3]);<br /> setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, len);<br /> addr.sin_family = AF_INET;<br /> addr.sin_addr.s_addr = inet_addr(argv[1]);<br /> addr.sin_port = htons(atoi(argv[2]));<br /> if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {<br /> if (errno == EINPROGRESS) {<br /> fprintf(stderr, "timeout/n");<br /> return -1;<br /> }<br /> perror("connect");<br /> return 0;<br /> }<br /> printf("connected/n");<br /> return 0;<br />}

 

執行結果:

xiaosuo@gentux perl $ ./a.out 10.16.101.1 90<br />1180290583<br />timeout<br />1180290586<br />xiaosuo@gentux perl $ ./a.out 10.16.101.1 90 2<br />1180290590<br />timeout<br />1180290592

 

和設想完全一致!


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.