自己動手實現socket的各種逾時控制

來源:互聯網
上載者:User
文章目錄
  • 連線逾時

在高並發的網路編程中,如果對socket的逾時不加以控制,程式會死的很辛苦。

在這裡,需要控制逾時時間的地方基本上分為三個部分:連線逾時、讀逾時以及寫逾時。

下面將按照上述逾時問題依次解決之。

連線逾時處理連線逾時有若干種方案,第一種比較trick, 使用socket本身的屬性進行設定。可以使用該屬性進行設定的原因是connect的核心實現(源檔案地址)採用了如下的實現方式:
 /*  *      Connect to a remote host. There is regrettably still a little  *      TCP 'magic' in here.  */ int __inet_stream_connect(struct socket *sock, struct sockaddr *uaddr,                           int addr_len, int flags) {        //省略之前的代碼        timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);          if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {                 int writebias = (sk->sk_protocol == IPPROTO_TCP) &&                                 tcp_sk(sk)->fastopen_req &&                                 tcp_sk(sk)->fastopen_req->data ? 1 : 0;                  /* Error code is set above */                 if (!timeo || !inet_wait_for_connect(sk, timeo, writebias))                         goto out;                  err = sock_intr_errno(timeo);                 if (signal_pending(current))                         goto out;         }         //省略之後的代碼 } EXPORT_SYMBOL(__inet_stream_connect);

該函數的實現使用了socket的發送逾時時間的設定。

因此,對connect進行逾時控制的時候,可以採用如下的代碼對socket的發送逾時時間進行設定,具體流程可以描述為:
  1. 建立socket
  2. 使用setsockopt函數設定socket的具體設定,在這裡設定發送逾時
  3. 最後使用connect執行串連的操作。
代碼如下:
    int sock_fd = socket(AF_INET, SOCK_STREAM, 0);     if (sock_fd < 0) {        perror("create sock_fd");        exit(-1);    }       struct sockaddr_in addr;    bzero(&addr,sizeof(addr));    addr.sin_family = AF_INET;    addr.sin_port=htons(g_conf.aod_port);    addr.sin_addr.s_addr = inet_addr(g_conf.aod_host);    struct timeval timeo = {0, 0};     socklen_t len = sizeof(timeo);    timeo.tv_usec = 10*1000;//10ms    setsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, len);    if(connect(sock_fd, (sockaddr*)&addr,sizeof(addr))<0){        fprintf(,stdout,"%s","CONNECT WITH AOD SERVER FAILED");        return -1;    }
另外一種對connect設定逾時的方法是使用網上廣為流傳的select/poll方法。這種方法來自於connect函數的manuel,使用man connect,可以看見connect函數傳回值的如下描述:
       EINPROGRESS              The  socket  is non-blocking and the connection cannot be completed immediately.  It is possible to select(2) or              poll(2) for completion by selecting the socket for writing. After select(2) indicates writability, use  getsock-              opt(2)  to  read  the  SO_ERROR option at level SOL_SOCKET to determine whether connect() completed successfully              (SO_ERROR is zero) or unsuccessfully (SO_ERROR is one of the usual error codes listed here, explaining the  rea-              son for the failure).

根據上述的描述,我們可以使用connect的傳回值做一些文章,從而完成對connect的設定。其實上述的手冊已經給定了一個實現connect逾時設定的基本步驟,這種方法比之前的方法複雜一些:

  1. 建立socket的檔案描述符
  2. 將socket設定為非阻塞的串連模式
  3. 調用connect函數,對connect的傳回值進行判定
  4. 使用select檢查該socket的檔案描述符是否可寫
  5. 將socket重新設定為阻塞的模式

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.