Connect Timeout:
Currently, the common method for setting SOCKET connect timeout on each platform is to use select (). The specific method is as follows:
1. Establish socket;
2. Set the socket to non-blocking mode;
3. Call connect ();
4. Use select () to check whether the socket descriptor is writable;
5. Determine the connect () result based on the result returned by select;
6. set socket back to blocking mode.
The following shows the client program I wrote (Compiled ):
# Include <stdio. h>
# Include <stdlib. h>
# Include <errno. h>
# Include <string. h>
# Include <sys/types. h>
# Include <netdb. h>
# Include <netinet/in. h>
# Include <sys/socket. h>
# Include <sys/Wait. H>
# Include <sys/time. h>
# Include <unistd. h>
# Include <ASM/IOCTLs. h>
# Define maxdatasalize 4926
Int detect_imap (const char * server, char * protocol, unsigned short port)
{
Int sockfd, numbytes;
Char Buf [maxdatasize];
Struct hostent * He;
Struct sockaddr_in their_addr;
If (He = gethostbyname (server) = NULL)
{
Herror ("gethostbyname ");
Return 0;
}
If (sockfd = socket (af_inet, sock_stream, 0) =-1)
{
Perror ("socket ");
Return 0;
}
Unsigned long ul = 1;
Int Rm = IOCTL (sockfd, fionbio, & UL );
If (Rm =-1)
{
Close (sockfd );
Return 0;
}
Their_addr.sin_family = af_inet;
Their_addr.sin_port = htons (port );
Their_addr.sin_addr = * (struct in_addr *) He-> h_addr );
Bzero (& (their_addr.sin_zero), 8 );
If (connect (sockfd, (struct sockaddr *) & their_addr, sizeof (struct sockaddr) = 0)
{
Printf ("connected/N ");
}
If (errno! = Einprogress)
{
Perror ("Connect ");
Printf ("cannot connect: % s/n", server );
Return 0;
}
Struct timeval timeout;
Fd_set R;
Fd_zero (& R );
Fd_set (sockfd, & R );
Timeout. TV _sec = 0;
Timeout. TV _usec = 100;
Int retval = select (sockfd + 1, null, & R, null, & timeout );
If (retval =-1)
{
Perror ("select ");
Return 0;
}
Else if (retval = 0)
{
Fprintf (stderr, "timeout/N ");
Return 0;
}
Printf ("% sconnected/N", server );
Unsigned long ul1 = 0;
Rm = IOCTL (sockfd, fionbio, (unsigned long *) & ul1 );
If (Rm =-1)
{
Close (sockfd );
Return 0;
}
If (numbytes = Recv (sockfd, Buf, maxdatasize, 0) =-1)
{
Perror ("Recv ");
Return 0;
}
Buf [numbytes] = '/0 ';
If (0 = strncmp (BUF, "* OK", 4 ))
{
Printf ("Received: % s", Buf );
Close (sockfd );
Return 1;
}
Else
{
Printf ("error protocol! ");
Close (sockfd );
Return 0;
}
}
Int
Main (INT argc, char * argv [])
{
Int I;
If (argc! = 2)
{
Fprintf (stderr, "Usage: client hostname/N ");
Exit (1 );
}
I = detect_imap (argv [1], argv [2], 143 );
Printf ("% d", I );
}
The above code works well and you can also use getsockopt () to obtain the exact information about a connection error. However, this method is complicated, the reason is that it involves canceling and resetting the blocking status.
Here is a simple operation method. You can also set the connection Timeout: that is, you can skip the select operation through the so_sndtimo Character Set parameter.
The reason is: the connect timeout parameter in the Linux kernel source code is the same as that in the so_sndtimo operation.
Therefore, on Linux, you can set so_sndtimo before connect to control connection timeout.
Some Correction Codes are as follows:
Struct timeval timeo;
Socklen_t Len = sizeof (timeo );
Timeo. TV _sec = overtime;
If (setsockopt (sockfd, sol_socket, so_sndtimeo, & timeo, Len) =-1)
{
Strcpy (reason, strerror (errno ));
Perror ("setsockopt ");
Return 0;
}
Their_addr.sin_family = af_inet;
Their_addr.sin_port = htons (serverstruct-> port );
Their_addr.sin_addr = * (struct in_addr *) He-> h_addr );
Bzero (& (their_addr.sin_zero), 8 );
If (connect (sockfd, (struct sockaddr *) & their_addr, sizeof (struct sockaddr) =-1)
{
If (errno = einprogress)
{
Strcpy (reason, "timeout ");
Return 0;
}
Strcpy (reason, strerror (errno ));
Perror ("Connect ");
Return 0;
}
Compile and run: GCC client_select.c-O client_select
./Client_select imap.21cn.com
PS: column is the code used to analyze the IMAP protocol.
Recv Timeout:
If you want to set the receiving timeout, you can use setsockopt () and send timeout, just add the following code after connect.
Timeout. TV _sec = 0;
Timeout. TV _usec = 500;
Int result = setsockopt (sockfd, sol_socket, so_rcvtimeo, (char *) & timeout. TV _sec, sizeof (struct timeval ));
If (result <0)
{
Perror ("setsockopt ");
}