文章目錄
在高並發的網路編程中,如果對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的發送逾時時間進行設定,具體流程可以描述為:
- 建立socket
- 使用setsockopt函數設定socket的具體設定,在這裡設定發送逾時
- 最後使用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逾時設定的基本步驟,這種方法比之前的方法複雜一些:
- 建立socket的檔案描述符
- 將socket設定為非阻塞的串連模式
- 調用connect函數,對connect的傳回值進行判定
- 使用select檢查該socket的檔案描述符是否可寫
- 將socket重新設定為阻塞的模式