Connect with non-blocking sockets

Source: Internet
Author: User
Tags goto readable set socket

Oh, someone came across the same questions as me, citing the following:

This is the URL:

http://cache.baidu.com/c?m= 9f65cb4a8c8507ed4fece763104c8c711923d030678197027fa3c215cc79031c1d3aa5ec76780d548d98297a5ae91e03f7fb36253d0070e49fcfdf4fd 9b8c37c79832433704bd14510c419d891007a9f34d507a9f916f0ccf125e2afc5d2af4323cf44747f97f1fb4d7611dd18fa0340e9b1ed38025e60ad9d 37728e5f6028ef621de71eaea6256e76d0ab81001b926c&p=9362d115d9c043fd0be290626159&user=baidu&fast=y

This is the original:

Linux client Socket non-blocking Connect programming (body)/* Development process and Source analysis

Development test Environment: virtual machine centos,windows Network debugging assistant

Non-blocking mode has 3 different uses

1. Three handshake at the same time to do other processing. Connect takes a roundtrip time to complete, from a few milliseconds of LAN to hundreds of milliseconds or a few seconds of WAN. 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. Because the program uses Select to wait for the connection to complete, you can set a select wait time limit to shorten the Connect timeout period. In most implementations, the timeout for connect is between 75 seconds and a few minutes.   Sometimes the program wants to end up waiting for 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 to communicate with the other host through the establishment of a thread, if the established thread uses blocking connect and remote communication, when there are hundreds of threads concurrency, due to network delays and all blocked, blocked threads will not release the system's resources, At the same time, the system will no longer allow the creation of new threads when the thread exceeds a certain number of times (each process has limited threads due to process space), and if a non-blocking connect is used, the connection fails to wait for a short time with the Select, and if the thread is not connected, it immediately ends the Prevent a large number of threads from blocking and causing the program to crash.

At present, the general idea of Connect non-blocking programming is:

When a TCP sleeve interface is set to Non-blocking, the call Connect,connect returns a einrpocess error in the system-supplied errno variable, at which point the TCP's three-way handshake continues. You can then use the Select function to check whether the connection was successful. The following experiment is based on UNIX network programming and the general example given on the network, after a lot of testing, found that there are many methods, in Linux, does not apply.

I first gave the important source of the step-by-step analysis, at the end of the complete connect non-blocking source.

1. First fill in socket structure, including remote IP, 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. Establish socket SOCKET:

if ((SOCKFD = socket (af_inet, sock_stream, 0)) = = 1)

{

Perror ("Socket creat error");

return 1;

}

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

Flags = FCNTL (sockfd,f_getfl,0);//Get 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 is established immediately return-1, while the errno (containing errno.h can be used directly) set to Einprogress, indicating that TCP three handshake is still in progress, If errno is not einprogress, the connection error, the program ends.

When the client and server on the same host, connect back to the end immediately, and return 0; No wait, so use the Goto function to skip the Select Wait function and go directly to the processing part after the connection. */

if ((n = Connect (sockfd, (struct sockaddr *) &serv_addr, sizeof (struct sockaddr))) < 0)

{

if (errno!= einprogress) 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 in the background connection, here you need to note that using Select to listen for the socket descriptor is readable or writable, if only writable, the connection is successful, you can do the following operation. If the descriptor is both readable and writable, divided into two cases, the first case is the socket connection error (do not ask why, this is the system, it is possible to read writable when the Connect connection is successful after the remote host disconnected close (socket)), In the second case, the Connect connection is successful, and the socket read buffer gets the data sent by the remote host. It is necessary to return the value of the errno after connecting to the connection, or by calling getsockopt (Sockfd,sol_socket,so_error,&error,&len); function return value to determine whether an error occurred, there is a portability problem, an error returns 1 in Solaris, but may return 0 in other systems. I first implement the UNIX network programming 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, getsockopt return -1,return-1, the program ends. The network returns 0 in normal time and the program continues to execute.

However, I am under Linux, no matter whether the network error, getsockopt always return 0, do not return 1, indicating that Linux and UNIX network programming is still slightly different. This means that the code does not work when the socket descriptor is readable and writable. Unable to detect if network failure occurred.

My test method is that when the call to connect, sleep (2) Hibernate 2 seconds, with these two seconds to disconnect the network assistant, this time the select returned 2, indicating that the set interface is readable and writable, should be a network connection error situation.

At this point, getsockopt returns 0, which does not work. Gets the value of the errno, indicated as einprogress, does not return the UNIX network programming said enotconn,einprogress indicates an attempt to connect, cannot indicate that the network has failed to connect.

In this case, there are 3 other methods in UNIX network programming, and these 3 methods are also the common non-blocking connect examples given on the network:

A. Call connect once more. Failure to return errno is eisconn the success of the connection, indicating that the connect has just succeeded, or return failure. The code is as follows: * *

int CONNECT_OK;

Connect (SOCKFD, (struct sockaddr *) &serv_addr, sizeof (struct sockaddr));

Switch (errno)

{

Case Eisconn://connect OK

printf ("Connect ok/n");

CONNECT_OK = 1;

Break

Case Ealready:

connect_0k =-1

Break

Case einprogress://are connecting, need to check again

CONNECT_OK =-1

Break

Default

printf ("Connect fail err=%d/n", errno);

CONNECT_OK =-1;

Break

}

/* As shown in the program, according to the errno return value of the call will be CONNECT_OK the value of the following processing, CONNECT_OK for 1 continue to perform other operations, or the end of the program.

But this method I tested in Linux, when the error occurred, the socket descriptor (my program is SOCKFD) into a readable and writable, but the second call to connect, errno did not return Eisconn, and did not return the connection failed error, is still einprogress, and when the network does not fail, the second use of Connect also return einprogress, so can not connect again to determine the success of the connection.

B.unix network programming said that using the Read function, if the failure, indicating connect failure, the return of the errno indicates the reason for failure, but this method does not work on Linux, Linux when the socket descriptor is readable to write, read returns 0, and does not put errno as an error.

C.unix network programming said that using the Getpeername function, if the connection failed, call the function, through the errno to determine the success of the first connection, but I tried, regardless of whether the network connection is successful, errno have not changed, are einprogress, can not judge.

Sadly, even if you call the Getpeername function, the getsockopt function still doesn't work.

In a comprehensive way, since you can't know for sure if Non-blocking Connect is successful, I send it directly when the descriptor is readable and writable, and I can determine whether it is successful by getting the server's return value. (If the server-side design doesn't send data, it's sad.) )

Program writing form for portability, according to the UNIX network programming recommended, using GETSOCKETOPT to judge, but not by the return value to judge, and through the function of the return parameters to judge.

6. Use Select to view receive descriptor, if readable, read data, end of program. When receiving data, note that the previous rset should be assigned to the descriptor first, because the select will clear the RSet, and when the Select is invoked, if the socket does not become readable, then RSet is zeroed in the select. So if you use RSet in your program, it's a good idea to reassign rset when you use it.

The procedure is as follows: * *

Fd_zero (&rset);

Fd_set (Sockfd,&rset);//If the previous select uses RSet, it is best to reassign the value

if ((n = select (Sockfd+1,&rset,null, null,&tval)) <= 0)

{

Close (SOCKFD);

return-1;

}

if ((Recvbytes=recv (SOCKFD, buf, 1024, 0)) ==-1)

{

Perror ("recv error!");

Close (SOCKFD);

return 1;

}

printf ("Receive num%d/n", recvbytes);

printf ("%s/n", buf);

*/

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.