1. Preface
Recently, a test tool has been written that requires fast and efficient scanning of which ports are open to each server. At that time, Ping can only detect IP, determine the server network is connected, but not to determine whether the port is open. We know that the port belongs to the application layer of the network, so need to use IP and port to detect, this time can be detected with connect, for the TCP protocol, the Connect function to carry out a TCP three handshake, if Connect is successful, then the server opened a port, If connect fails, the server is not opening a port. The Connect failure is controlled by a timeout, and in the specified time, connect initiates multiple connections and executes until time-out before returning an error. By default, connect is blocked, and the default time-out is 75s, and under normal circumstances, the connectivity of the detection network is millisecond, and if you want to judge 100,000 servers, it is inefficient to do so with the blocking default of connect. Therefore, a non-blocking connect is used and a custom timeout is required (my custom time-out is 5s).
2. Non-blocking Connect
For a blocking socket, calling the Connect function fires the three-time handshake of TCP and returns only if the connection succeeds or fails, and for non-blocking sockets, if the call to the Connect function returns 1 (indicating an error), and the error is einprogress, Indicates that the connection was established, started but not completed, and if 0 is returned, the connection is established, typically when the server and the client are on the same host.
Select is an IO multiplexing mechanism that allows a process to instruct the kernel to wait for any one of multiple events to occur, and to wake it up after one or more events occur or after a specified period of time has passed. The connect itself does not have a timeout function, and if you want to set a timeout on the IO operation of the socket, you can use the Select function.
For select and nonblocking Connect, note two: [1] When the connection is successfully established, the descriptor becomes writable, [2] When the connection is established, the descriptor becomes readable and can be written, in which case the getsockopt function can be called.
3. Implementation steps
(1) Create the socket and use FCNTL to set it to non-blocking
(2) Call the Connect function, if return 0, the connection is established, if return-1, check errno, if the value is einprogress, the connection is being established.
(3) In order to control the connection settling time, the socket descriptor is added to the read-only writable collection of select, and a timeout is set by the Select function.
(4) If the specified time is successfully established, the descriptor becomes writable; otherwise, the error message is captured with the getsockopt function
(5) Restore the file status of the socket and return it.
The test code looks like this:
1#include <stdio.h>2#include <stdlib.h>3#include <string.h>4#include <unistd.h>5#include <sys/types.h>/*See NOTES*/6#include <sys/socket.h>7#include <netinet/inch.h>8#include <fcntl.h>9#include <errno.h>Ten One intMainintargcChar**argv) A { - if(ARGC <3) { -printf"Please input IP and port, for example./main 120.12.34.56 80.\n"); the return-1; - } - - + Char*IPADDR = argv[1]; -UnsignedintPort = atoi (argv[2]); + A intFD =0; at structsockaddr_in addr; - fd_set FDR, FDW; - structtimeval timeout; - intErr =0; - intErrlen =sizeof(err); - inFD = socket (Af_inet,sock_stream,0); - if(FD <0) { tofprintf (stderr,"Create socket failed,error:%s.\n", Strerror (errno)); + return-1; - } the *Bzero (&ADDR,sizeof(addr)); $addr.sin_family =af_inet;Panax NotoginsengAddr.sin_port =htons (port); -Inet_pton (Af_inet, IPADDR, &addr.sin_addr); the + /*set socket as non-blocking*/ A intFlags = FCNTL (FD, F_GETFL,0); the if(Flags <0) { +fprintf (stderr,"Get Flags error:%s\n", Strerror (errno)); - Close (FD); $ return-1; $ } -Flags |=O_nonblock; - if(Fcntl (FD, F_SETFL, flags) <0) { thefprintf (stderr,"Set Flags error:%s\n", Strerror (errno)); - Close (FD);Wuyi return-1; the } - Wu /*Linux system default time-out is 75s in case of blocking*/ - intrc = Connect (FD, (structsockaddr*) &addr,sizeof(addr)); About if(RC! =0) { $ if(errno = =einprogress) { -printf"Doing connection.\n"); - /*Processing Connection*/ -Fd_zero (&FDR); AFd_zero (&FDW); +Fd_set (FD, &FDR); theFd_set (FD, &FDW); -Timeout.tv_sec =Ten; $Timeout.tv_usec =0; therc =Select(FD +1, &FDR, &FDW, NULL, &timeout); theprintf"RC is:%d\n", RC); the /*Select call Failed*/ the if(RC <0) { -fprintf (stderr,"Connect error:%s\n", Strerror (errno)); in Close (FD); the return-1; the } About the /*Connection timed out*/ the if(rc = =0) { thefprintf (stderr,"Connect timeout.\n"); + Close (FD); - return-1; the }Bayi /*[1] When the connection is successfully established, the descriptor becomes writable, rc=1*/ the if(rc = =1&& Fd_isset (FD, &FDW)) { theprintf"Connect success\n"); - Close (FD); - return 0; the } the /*[2] When the connection is established encountered an error, the descriptor becomes readable, can also be written, rc=2 encountered this situation, can call the GetSockOpt function*/ the if(rc = =2) { the if(GetSockOpt (FD, Sol_socket, So_error, &err, &errlen) = =-1) { -fprintf (stderr,"getsockopt (so_error):%s", Strerror (errno)); the Close (FD); the return-1; the 94 } the the if(err) { theerrno =err;98fprintf (stderr,"Connect error:%s\n", Strerror (errno)); About Close (FD); - return-1;101 102 }103 }104 the } 106fprintf (stderr,"Connect failed, error:%s.\n", Strerror (errno));107 return-1;108 } 109 return 0; the}
4. References
http://dongxicheng.org/network/non-block-connect-implemention/
Http://www.cnblogs.com/flyxiang2010/archive/2010/12/17/1909051.html
"Summary" of Connect timeout processing under Linux