Linux non-blocking connect function

Source: Internet
Author: User
Tags goto readable htons

Development test Environment: virtual machine centos,windows Network debugging assistant
Non-blocking mode has 3 uses
1. Three-time handshake to do other processing at the same time. Connect takes a round trip time, from a few milliseconds of LAN to a WAN of hundreds of milliseconds or a few seconds. There may be some other processing to be performed during this time, such as data preparation, preprocessing, etc.
2. Use this technique to establish multiple connections. This is common in Web browsers.
3. As the program waits for the connection to complete with SELECT, a select wait time limit can be set to shorten the connect time-out. In most implementations, the time-out for connect is between 75 seconds and a few minutes.   Sometimes the program wants to end in a certain amount of time, using non-blocking connect to prevent blocking for 75 seconds, especially in multithreaded network programming. For example, there is an application that makes socket communication with other hosts by establishing a thread, and if the established thread uses blocking connect and remote communication, when there are hundreds of threads concurrently, the blocked thread will not release the system's resources because of the network delay and all the blocked threads. At the same time when the blocking thread exceeds a certain number of times, the system will no longer allow the creation of new threads (each process due to the reason of the process space is limited), if the use of non-blocking connect, connection failure using select wait for a short time, if not connected, the thread immediately end the release of resources, Prevents a large number of threads from blocking and crashes the program.
The general idea of connect non-blocking programming today is:
When a TCP socket is set to non-blocking, calling Connect,connect returns a einrpocess error in the system-supplied errno variable, at which time the three-way handshake of TCP continues. You can then use the Select function to check if the connection is successful. The following experiments are based on UNIX network programming and a common example given on the network, and after a lot of testing, there are many methods that are not applicable in Linux.
I first gave the important source of the stepwise analysis, in the end to give a complete connect non-blocking source.
1. First fill in the socket structure, including the remote IP, the communication port is as follows: */

struct sockaddr_in serv_addr;serv_addr.sin_family=af_inet;serv_addr.sin_port=htons (9999); Serv_addr.sin_addr.s_ Addr = inet_addr ("58.31.231.255"); Inet_addr converted to network byte order bzero (& (Serv_addr.sin_zero), 8);



2. Set up socket sockets:

if (SOCKFD = socket (af_inet, sock_stream, 0)) = =-1) {perror ("Socket creat error"); return 1;}



3. Make the socket non-blocking, at which point the socket is set to non-blocking mode

Flags = FCNTL (sockfd,f_getfl,0);//Gets the current state of the established SOCKFD (non-blocking) fcntl (sockfd,f_setfl,flags| O_nonblock);//Set current SOCKFD to non-blocking



/*4. Establish connect connection, when the socket is set to non-blocking, connect call, regardless of whether the connection establishes an immediate return-1, while the errno (including errno.h can be used directly) is set to Einprogress, indicating that the TCP three handshake is still in progress, If errno is not einprogress, then the connection error, the program ends.
When the client and server are on the same host, connect returns to the end immediately, returning 0, without waiting, so use the Goto function to skip the Select Wait function and go directly to the connected Processing section. */

if (n = Connect (sockfd, (struct sockaddr *) &serv_addr, sizeof (struct sockaddr))) < 0) {if (errno! = Einprogre SS)    return 1;} if (n==0) {printf ("Connect completed immediately"); goto done;}



/* 5. Set the wait time, use the Select function to wait for the Connect function that is connected in the background, it is necessary to explain that using Select to listen to the socket descriptor is readable or writable, if only writable, indicating that the connection is successful, you can do the following. If the descriptor is both readable and writable, in two cases, the first case is the socket connection error (do not ask why, this is the system, the readable can be written when the remote host disconnected when the connection close (socket)), The second case is that the connect connection succeeds, and the socket read buffer gets the data sent by the remote host. The value to be returned to errno after connect is connected, or by calling getsockopt (Sockfd,sol_socket,so_error,&error,&len); function return value to determine if an error occurred, there is a portability issue where an error in Solaris returns-1, but may return 0 in other systems. I first implemented the UNIX network programming source code. as follows: */

Fd_zero (&rset); Fd_set (sockfd,&rset); wset = Rset;tval.tv_sec = 0;tval.tv_usec = 300000;int error;socklen_t len;if (n = Select (sockfd +1, &rset, &wset, null,&tval)) <= 0) {printf ("Time Out Connect error"); Close (sockfd); return-1;} If (Fd_isset (sockfd,&rset) | | Fd_isset (sockfd,&west)) {len = sizeof (error); if (getsockopt (Sockfd,sol_socket,so_error,&error,&len) <0) return 1;}


/* Here I tested, according to the UNIX network programming description, when the network error occurs, GETSOCKOPT returns -1,RETURN-1, the program ends. The network normally returns 0, and the program continues to execute.
But I am under Linux, regardless of whether the network error, getsockopt always return 0, do not return-1, the Linux and UNIX network programming is still a little bit different. This code does not work when the socket descriptor is readable and writable. The network could not be detected for failure.
I test the method is, when the call to connect, sleep (2) sleep 2 seconds, with the help of this two seconds to disconnect the network assistant, when Select returns 2, indicating that the socket interface readable and writable, should be a network connection error situation.
At this point, getsockopt returns 0, which does not work. Gets the value of errno, which indicates that einprogress is not returned in UNIX network programming, saying that the enotconn,einprogress is trying to connect and cannot indicate that the network has failed to connect.
In this case, there are 3 other methods that are presented in UNIX network programming, and these 3 methods are also common non-blocking connect examples given on the network:
A. Call connect again once. Failure to return errno is eisconn that the connection was successful, indicating that the connect was successful, otherwise the return failed. The code is as follows: */

int Connect_ok;connect (SOCKFD, (struct sockaddr *) &serv_addr, sizeof (struct sockaddr)); switch (errno) {case Eisconn  :   //connect okprintf ("Connect OK \ n"), CONNECT_OK = 1;break;case ealready:connect_0k = -1break;case einprogress://IS Connecting, need to check AGAINCONNECT_OK = -1break;default:printf ("Connect fail err=%d \ n", errno); CONNECT_OK = -1;break ;}


/* As shown in the program, the following processing is performed based on the value of the CONNECT_OK returned by the errno return value, CONNECT_OK 1 to continue with other operations, or the program ends.

But this method I tested under Linux, when the error occurred, the socket descriptor (my program is SOCKFD) becomes readable and writable, but after the second call to connect, errno did not return Eisconn, and did not return the connection failed error, is still a einprogress, and when the network does not fail, the second use of the Connect connection also returns Einprogress, so it is not possible to connect again to determine whether the connection is successful.
B.unix network programming said to use the Read function, if it fails to indicate that connect failed, the returned errno indicates the reason for the failure, but this method does not work on Linux, Linux when the socket descriptor is readable writable, read returns 0, and does not set errno as an error.
C.unix network programming said to use the Getpeername function, if the connection failed, call the function, through the errno to determine whether the first connection is successful, but I tried, regardless of whether the network connection is successful, errno has not changed, all for einprogress, cannot judge.
Sadly, even if you call the Getpeername function, the getsockopt function is still not working.
In summary, since it is not clear whether the non-blocking connect is successful, I send it directly when the descriptor is readable and writable, and determine whether it succeeds by getting the return value of the server. (If the server-side design doesn't send data, it's sad.) )
The written form of the program is recommended for portability, according to UNIX network programming, using getsocketopt for judgment, but not by the return value, but by the return parameters of the function.

6. Use Select to view the receive descriptor, if readable, to read the data, the program ends. When receiving data, note that the previous rset is re-assigned to the descriptor, because select will clear the RSet, and when select is called, if the socket is not readable, RSet will be zeroed in the select. So if you use RSet in your program, it's a good idea to re-assign the RSet when you use it.
The program is as follows: */

Fd_zero (&rset); Fd_set (Sockfd,&rset);//If the previous select uses RSet, it is best to re-assign the IF (n = select (Sockfd+1,&rset,null, null,&tval)) <= 0 {Close (SOCKFD); return-1;} if ((Recvbytes=recv (SOCKFD, buf, 1024x768, 0)) ==-1) {perror ("recv error!"); Close (SOCKFD); return 1;} printf ("Receive num%d\n", recvbytes);p rintf ("%s\n", buf);

The complete code for non-blocking connect is summarized as follows:

Intmain (int argc, char** argv) {intsockfd,recvbytes,res,flags,error,n;socklen_tlen;fd_setrset,wset; Structtimevaltval;tval.tv_sec=0;tval.tv_usec=300000;structsockaddr_inserv_addr;char*senddata= "1234567890";// Send string charbuf[1024]= "/0"; Receive buffer//Create socket descriptor if ((SOCKFD = socket (af_inet, sock_stream, 0)) = =-1) {perror ("socket create failed"); return1;} Serv_addr.sin_family=af_inet;serv_addr.sin_port=htons (9999); Serv_addr.sin_addr.s_addr=inet_addr ("58.31.231.255 "); Bzero (& (Serv_addr.sin_zero), 8); Flags=fcntl (sockfd,f_getfl,0); Fcntl (sockfd,f_setfl,flags| O_nonblock);//set to non-blocking if (res = connect (sockfd, (struct sockaddr *) &serv_addr, sizeof (struct sockaddr))) < 0) {if ( errno! = einprogress) {return1;}} If the server and client are on the same host, some environments socket set to non-blocking will return 0if (0 = = res) goto done; Fd_zero (&rset); Fd_set (Sockfd,&rset); Wset=rset;if ((res = select (Sockfd+1, NULL, &wset, null,&tval)) <= 0) {perror (" Connect time out/n "); Close (sockfd); return1;} Else{len=sizeof (error); GetSockOpt (SOCKFD, Sol_sockeT, So_error, &error, &len); if (error) {fprintf (stderr, "Error in connection ()%d-%s/n", Error, Strerror (error)); r Eturn1;}} Done:if ((n = Send (SOCKFD, SendData, strlen (SendData), 0)) ==-1) {perror ("Send error!"); Close (SOCKFD); return1;} if (n = select (Sockfd+1,&rset,null, null,&tval)) <= 0)//rset has not been used and is not reset to Sockfd{perror ("Receive Time Out or C Onnect error "); Close (sockfd); return-1;} if ((Recvbytes=recv (SOCKFD, buf, 1024x768, 0)) ==-1) {perror ("recv error!"); Close (SOCKFD); return1;} printf ("Receive num%d/n", recvbytes);p rintf ("%s/n", buf);}

Linux non-blocking connect function

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.