Students who have written network programs should all know the connect function. Before the socket starts reading and writing operations, it is necessary to connect, that is, the TCP three-time handshake. This process is completed in the connect function. The connect function itself is blocked. The asynchronous connect function can be realized by setting the socket options and calling the select/poll function
socket is in blocking mode by default. When it is in blocking mode, after calling the connect function, it will wait until the connection result is returned. It will either succeed or fail. When the connect function returns 0, it will succeed and return - 1 failure
In LAN, calling connect function basically returns results immediately. When the server is abroad, connect function will block for a period of time, about a few seconds, the specific time depends on the network condition at that time.
Why use asynchronous connect
The default timeout of connect under Linux is about one minute (slightly different from different Linux versions). In actual development, this time seems a little long
For the server, it needs to serve many clients and minimize blocking. Therefore, asynchronous connect technology is generally adopted
For every student who writes a network program, asynchronous connect should be the basic skill that must be mastered
Asynchronous connect steps
(1) establish socket,call fcntl The function sets it to non blocking (2) call connect Function, returning 0 indicates that the connection is successful, and -1,Need to check the error code If the error code is EINPROGRESS,Indicates that a connection is being established If the error code is EINTR Indicates that a system interrupt has occurred. At this time, you can continue to execute the connection If it is another error code, call close(fd) Function close socket, connection failed (3) take socket join select/poll And set the timeout (4) judge select/poll Return value of function Less than or equal to 0 indicates failure Others, indicating socket Writable, call getsockopt Function capture socket Error message for
The specific codes are as follows:
/* Asynchronous connect test code, test_connect.cpp */ #include <stdint.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/select.h> #include <poll.h> #include <sys/un.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <arpa/inet.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <netdb.h> #include <errno.h> #include <stdarg.h> #include <poll.h> #include <limits.h> #include <iostream> using namespace std; int32_t main(int32_t argc, char *argv[]) { if(argc < 3) { std::cout << "argc < 3..." << std::endl; return -1; } std::string strip = argv[1]; uint32_t port = atoi(argv[2]); //Create socket int32_t fd = socket(AF_INET, SOCK_STREAM, 0); if(-1 == fd) { std::cout << "create socket error:" << errno << std::endl; return -1; } //Set socket to non blocking int32_t flag = fcntl(fd, F_GETFL, 0); flag |= O_NONBLOCK; if(-1 == fcntl(fd, F_SETFL, flag)) { std::cout << " set socket nonblock error:" << errno << std::endl; close(fd); return -1; } //server address struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(strip.c_str()); // for(; ;) { //Connect server int32_t ret = connect(fd, (struct sockaddr*)&addr, sizeof(addr) ); if(-1 == ret) { int32_t err = errno; if(EINTR == err) { //connect was interrupted. Continue to retry //If EINTR errors are not handled, the connect logic may not be put into the for loop continue; } if(EINPROGRESS != err) { std::cout << "connect err:" << errno << ", str:" << strerror(errno) << std::endl; goto exit; } //Connecting std::cout << "connecting..." << std::endl; //Processing results int32_t result = -1; #if 1 //Add socket to writable set of poll struct pollfd wfd[1]; wfd[0].fd = fd; wfd[0].events = POLLOUT; //Check whether the socket is writable result = poll(wfd, 1, 3000); #elif 0 //Set timeout struct timeval tval; tval.tv_sec = 3; tval.tv_usec = 0; //Add socket to the writable set of select fd_set wfds; FD_ZERO(&wfds); FD_SET(fd,&wfds); //Check whether the socket is writable result = select(fd + 1, nullptr, &wfds, nullptr,&tval); #endif std::cout << "async connect result:" << result << std::endl; // fail if(result <= 0 ) { std::cout << "async connect err:" << errno << ", str:" << strerror(errno) << std::endl; goto exit; } //Check socket error information int32_t temperr = 0; socklen_t temperrlen = sizeof(temperr); if(-1 == getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&temperr, &temperrlen) ) { std::cout << "async connect...getsockopt err:" << errno << ", str:" << strerror(errno) << std::endl; goto exit; } if(0 != temperr) { std::cout << "async connect...getsockopt temperr:" << temperr << ", str:" << strerror(temperr) << std::endl; goto exit; } //success std::cout << "async connect success..." << std::endl; goto exit; } else { //Connection succeeded std::cout << "connect success..." << std::endl; goto exit; } } // end of for(; ;) exit: std::cout << "quit...." << std::endl; close(fd); return 0; }
- Code description
If the EINTR error is not handled, the connect function and the following logic can not be put into the for loop
Check whether the socket is writable by calling select or poll function. The poll function is used in the above code. Change #if 1 to #if 0 and #elif 0 to #elif 1 in the code, that is, use the select function to check whether the socket is writable
test
Execute the nc -l -v -k 192.168.70.20 5000 command on another machine to start a server program
Execute G + + - G - wall - STD = C + + 11 - O test on the current machine_ connect test_ Compile with connect.cpp
Execute. / test_connect 192.168.70.20 5000, and the results are shown in the figure below
At this time, the server program is displayed as follows:
Pass test_ The screenshot of the connect program can be seen that after calling the connect function, the EINPROGRESS error code is returned, then the select/poll function is returned to 1, indicating that socket is writable, and then the getsockopt function is called to check the socket error information. By printing the information, socket knows no error information, that is, the connection is successful.
We press CTRL + C on the server machine to stop the server program, and then close test_connect program and execute. / test again_ Connect 192.168.70.20 5000, and the results are as follows:
As can be seen from the above figure, even if the server program has exited, the socket is returned writable after calling select/poll. When you continue to call getsockopt function to check the socket error code, the error code is 111, indicating that the connection is rejected, that is, the connection fails
A very important point to note here is that on Linux, even if the socket is not connected successfully, when you call select/poll, it still returns that the socket is writable. Therefore, in addition to calling select/poll to check that the socket is writable, you also need to call getsockopt function to check the error code of the socket. An error code of 0 indicates that the connection is successful, and others indicate that the connection fails