Description: This article applies to the Windows platform, followed by an additional application for Linux platform
Turn from: http://www.cnblogs.com/shiqgfmj/archive/2010/12/29/1919434.html
Non-blocking socket client connect () has been bothering you for the whole afternoon. Because it is non-blocking, it is not possible to know when to connect, regardless of whether the connection is directly returned.
The first thought to find information online, unfortunately not much. So MSDN, finally found a sentence.
With a nonblocking socket, the connection attempt cannot is completed immediately. In the, this function would return socket_error and WSAGetLastError'll resturn Wsaewouldblock. The following list shows the three scenarios that are possible in the:
Use the ' SELECT ' function to determine the completion of the ' connection ' request by checking to the ' if ' is writeabl E.
If the application is using WSAEventSelect to indicate interest in connection events, then the associated event object wil L be signaled indicating this connect operation is complete (successfully or not).
Non-blocking socket connection requests do not complete immediately. At this point, the function returns SOCKET_ERROR and WSAGetLastError () returns WSAEWOULDBLOCK. Here are 2 scenarios for this scenario:
1, use the Select function to check whether this socket can be written to determine whether the connection request is complete;
2. If the program uses WSAEventSelect to show concern for connection events, then the associated event object will be signaled to indicate that the connection operation is complete (success or failure)
The small code is as follows:
Client.c [CPP] View Plain copy Fd_zero (&wtfds); _timout.tv_sec = 3; _timout.tv_usec = 0; msock = socket (af_inet, sock_stream, 0); toaddr.sin_family = af_inet; toaddr.sin_port = htons (7000); Toaddr.sin_addr. S_un. S_ADDR&NBSP;=&NBSP;INET_ADDR ("192.168.1.87"); if (ioctlsocket (msock, fionbio, &itemp) < 0 { perror (" ioctlsocket error\n "); } fd_set (Msock, &wtfds); Iret = connect (msock, (sockaddr*) &toaddr, sizeof (toaddr)); if (! IRet) { printf ("connect immediately\n"); char sndMsg[100] = {0}; sprintf (Sndmsg, "Hello world"); if (Socket_error == send ( Msock, sndmsg, strlen (sndmsg), 0)) { perror ("Send error"); return 1; } printf (" send success\n "); } else if (iret<0 && WSAGetLastError () ==wsaewouldblock) { int iRet1 = Select (0, null, &wtfds, null, &_timout); if (iret1 < 0) { perror ("connect error\n"); return 1; } else if (!IRET1) { perror ("timeout error\n "); return 1; } else { if (Fd_isset (Msock, &wtfds)) { printf ("connect success\n"); char sndMsg[100] = {0}; sprintf (sndmsg, "Hello world"); if (Socket_error == send (Msock, sndmsg, strlen) ( sndmsg), 0) { perror (" Send error "); return 1; } printf ("send success\n "); } } }
Server.c[CPP] View Plain copy msock = socket (af_inet, sock_stream, 0); ioctlsocket (msock, fionbio, (unsigned long*) &inonbk); fd_set (Msock, &rdfds); cltaddr.sin_family = af_inet; cltaddr.sin_port = htons (7000); CLTADDR.SIN_ADDR. S_un. s_addr = inaddr_any; if (Socket_error == bind msock, (SOCKADDR*) & Cltaddr, sizeof (CLTADDR)) { perror ("Bind error"); return 1; } if (socket_error == Listen (msock, 5)) { perror ("Listen error"); return 1; } _tim = Time (NULL); ltime = localtime (&_tim); PrintF ("%d:%d:%d\n", ltime->tm_hour, ltime->tm_min, ltime->tm_sec); Iret = select (0, &rdfds, null, null, &_timval); if (iret < 0) { perror ("Accept error"); return 1; } else if (iret == 0) { perror ("Timeout error"); return 1; } else { if (fd_ ISSET (Msock, &rdfds)) printf ("msock is in rdfds\n "); else return 1; SOCKET clsock = accept (msock, (sockaddr*) &cltaddr, &ilen); if (clsock == invalid_socket) { printf ("Clsock is not a valid socket\ n "); return 1; } if (Fd_isset (Clsock, &rdfds)) printf ("clsock is in rdfds\n"); else printf ("Clsock is not in rdfds\n "); _tim = time (NULL); ltime = localtime (&_tim); printf ("%d: %d:%d\n ", ltIME->TM_HOUR,&NBSP;LTIME->TM_MIN,&NBSP;LTIME->TM_SEC); char recvmsg[100] = {0}; int isize = recv (clsock, recvmsg, 100, 0); printf ("from client %s:%s,%d\n"), inet_ntoa (CLTADDR.SIN_ADDR), Recvmsg,wsagetlasterror ()); }
The following applies to the Linux platform
Turn from: http://kenby.iteye.com/blog/1183579
Step 1: Set non-blocking, start the connection
To achieve non-blocking Connect, the SOCKFD is first set to non-blocking. So call Connect can return immediately, handling three kinds of cases based on the return value and errno:
(1) If return 0, means connect success.
(2) If the return value is less than 0, errno is einprogress, indicating that the connection establishment has started but has not yet completed. This is the desired result, not the real mistake.
(3) If the return value is less than 0,errno is not einprogress, the connection is wrong.
Step 2: Judge readable and writable
The SOCKFD is then added to the read and write listening collection of Select, and the SOCKFD is determined by select
Can write, handle three kinds of situations:
(1) If the connection is established, the other party has no data to arrive, then SOCKFD is writable
(2) If the connection is established before the Select, and the other's data has arrived, then the SOCKFD is readable and writable.
(3) If the connection occurs incorrectly, SOCKFD is also readable and writable.
To determine whether connect is successful, you have to distinguish between (2) and (3), both of which are SOCKFD
Readable and writable, the distinguishing method is to call getsockopt to check for errors.
Step 3: Check for errors using the getsockopt function
GetSockOpt (SOCKFD, Sol_socket, So_error, &error, &len)
In cases where sockfd are both readable and writable, we use getsockopt to check the connection
Whether there was an error. But there's a portability problem here.
If an error occurs, the implementation of getsockopt originating from Berkeley will be in the variable error
Returns an error, getsockopt itself returns 0, but Solaris lets getsockopt return-1,
and save the error in the errno variable. So in order to judge whether there is a mistake, we have to deal with both of these situations.
Code:[CPP] View Plain copy int conn_nonb (int sockfd, const struct sockaddr_in *saptr, SOCKLEN_T&NBSP;SALEN,&NBSP;INT&NBSP;NSEC) { int flags, n, error, code; socklen_t len; fd_set wset; struct timeval tval; flags = fcntl (sockfd, f_getfl, 0); fcntl (Sockfd, f_setfl, flags | o_nonblock) ; error = 0; if (N == connect (sockfd, saptr, Salen)) == 0) { goto done; } else if (n < 0 && errno != einprogress) { return ( -1); } /* do whatever we want while the connect is taking place */ fd_zero (&wset); fd_set (SOCKFD, &wset); tval.tv_sec = nsec; tval.tv_usec = 0; &nBsp if (N = select (sockfd+1, null, &wset, null, nsec ? &tval : null) == 0) { close (SOCKFD); /* timeout */ errno = ETIMEDOUT; return (-1) ; } if (Fd_isset (sockfd, &wset)) { len = sizeof (Error); code = getsockopt (sockfd, sol_socket, so_error, & Error, &len); /* If an error occurs, the Solaris implementation getsockopt returns -1, * Set Pending error to Errno. berkeley implementation * getsockopt return 0, pending error back to error. * we need to deal with both situations */ if (code < 0 | | error) { close (SOCKFD); if (Error) errno = error; return ( -1); } } else { fprintf (stderr, "select error: sockfd not Set "); exit (0); } done: fcntl (sockfd, f_setfl, flags); /* restore file status flags */ return (0); }
about ioctlsocket ()
(Excerpt from: http://www.cnblogs.com/endeavour/archive/2011/11/18/2253529.html)
#include <winsock.h>
This function controls the I/O mode a socket.
int ioctlsocket (SOCKET s, long Cmd,u_long far* ARGP);
Parameters
S
[In] Descriptor identifying a socket.
Cmd
[In] Command to perform on socket s.
Argp
[In, out] Pointer to a parameter for CMD.
Return Value:
If No error occurs, this function returns zero. If An error occurs, a value of Socket_error are returned, and a specific error code can be retrieved by calling Wsagetlaste Rror. The following table shows a list of possible error codes.
U_long mode = 0;
Ioctlsocket (S,fionbio,&mode);
Control is blocking mode.
U_long mode = 1;
Ioctlsocket (S,fionbio,&mode);
Control is non-blocking.
This function can be used for any set of interfaces in any state. It is used to obtain the operation parameters related to the socket interface, and is independent of the specific protocol or communication subsystem. The following commands are supported:
Fionbio: The non-blocking mode of the set interface S is allowed or disallowed. ARGP points to an unsigned long integer. If non-blocking mode is allowed Non-zero, such as blocking non-blocking mode is zero. When you create a nested interface, it is in blocking mode (that is, non-blocking mode is blocked). This is consistent with the BSD socket interface. The Wsaasynselect () function automatically sets the socket interface to non-blocking mode. If a wsaasynselect () operation has been performed on a set of interfaces, any attempt to reset the set interface to blocking mode with ioctlsocket () will fail wsaeinval. In order to reset the socket to blocking mode, the application must first be wsaasynselect () called (ievent parameter 0) to Wsaasynselect ().
Fionread: Determines the amount of data that the sleeve interface s automatically reads. ARGP points to an unsigned long integer that contains the return value of ioctlsocket (). If S is the Socket_stream type, Fionread returns the amount of all the data received in one recv (). This is usually the same amount of data queued in the socket. If S is a sock_dgram type, the Fionread returns the first datagram size queued on the set interface.
Siocatmark: Is it true that all out-of-band data has been read in. This command applies only to the Sock_stream type of socket, and the set of interfaces has been set to receive Out-of-band data (so_oobinline) online. If no out-of-band data is waiting to be read, the operation returns True true. Otherwise, false false is returned, and the next recv () or recvfrom () operation retrieves some or all of the data before "tag". The application can use the Siocatmark action to determine if there is data left. If there is regular data before the "emergency" (out-of-band) data, the data is received sequentially (note that the recv () and recvfrom () operations do not confuse regular and out-of-band data in a single call. ARGP points to a bool, where ioctlsocket () is stored in the return value.