Implementation of socket connection timeout in Linux

Source: Internet
Author: User
Tags htons

Currently, the common methods for setting socket connection timeout for each platform are as follows:

  1. Create a socket and set it to a non-blocking state.
  2. Call connect to connect the peer host. If the connection fails, check whether errno is einprogress at the time, that is, whether the connection is in progress. If yes, go to step 3. If no, an error is returned.
  3. Use the SELECT statement to listen to the write-ready event of the socket within the specified timeout period. If the SELECT statement is listened to, the connection is successful. Otherwise, the connection fails.

The following is the sample code in 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/>}

 

The actual running result is as follows:

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

 

As you can see, the above Code works very well, and if you want to know the exact information when a connection error occurs, you can get it using getsocketopt:

Int error; <br/> socklen_t errorlen = sizeof (error); <br/> getsockopt (FD, sol_socket, so_error, & error, & errorlen );

 

However, it is somewhat complicated. If socket parameters like so_sndtimo/so_rcvtimo can skip the SELECT statement for timeout operations, the world will be better. Of course, you can also choose a library that provides simple interfaces like Apr, but here I will mention another method.

The introduction seems too long. When I read the Linux kernel source code, I accidentally found that the connect timeout parameter was consistent with the parameter operated with 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}

 

This means that on the Linux platform, you can set so_sndtimo before connect to control connection timeout. Write a test code:

# 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/>}

 

Execution result:

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

 

Exactly the same as the idea!


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.