您的位置:首页 > 其它

超时设置方法( the way to set timeout )

2015-11-09 02:28 323 查看
Tips:

In the connection between the server and the client. Sometimes there may have some timeout. Today , we used our own method to realise a series of timeout function , including read_timeout , write_timeout , accept_timeout and connect_timeout which is the
most difficult in four of them. We need to understand the different processing method of the timeout.

Client :

/************************************************************************
> filename : echocli.c
> Author: ma6174
> Mail: ma6174@163.com
> Created Time: Thu 29 Oct 16:38:57 2015
************************************************************************/

#include <fcntl.h>
#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>

#define ERR_EXIT(m) \
do \
{\
perror(m) ;\
exit(EXIT_FAILURE) ;\
}while(0)
/*
* read timeout --
* the function to test read timeout , not including read function.
* fd : file descriptor
* wait_senconds : the time to wait timeout,0 means that doesn't test timeout
* success(not timeout) return 0 ; failed return -1 with timeout return -1
* errno = ETIMEOUT
*/

int read_timeout ( int fd , unsigned int wait_seconds )
{
int ret ;
ret = 0 ;
if ( wait_seconds > 0 )
{
fd_set read_fdset ;
struct timeval timeout ;
FD_ZERO (&read_fdset ) ;
FD_SET ( fd , &read_fdset ) ;
timeout.tv_sec = wait ( wait_seconds ) ;
timeout.tv_usec = 0 ;
do
{
ret = select ( fd + 1 , &read_fdset , NULL , NULL , &timeout ) ;
}while( ret < 0 && EINTR == errno ) ;  // this occasion is interrupted by signal
if ( 0 == ret )
{
ret = -1 ;
errno = ETIMEDOUT ;
}
else if ( 1 == ret ) // fd creats an readable event
{
ret = 0 ;
}
}
return ret ;
}

/**
* write_timeout write timeout function , no including write
* fd : file descriptor
* wait_seconds : the time to wait timeout , if 0 = wait senconds means that it doesn't test timeout
* success(not timeout) return 0 ; failed return -1 with timeout return -1
*/

int write_timeout ( int fd , unsigned int wait_seconds )
{
int ret ;
ret = 0 ;
if ( wait_seconds > 0 )
{
fd_set write_fdset ;
struct timeval timeout ;

FD_ZERO ( &write_fdset ) ;
FD_SET ( fd  , &write_fdset ) ;
timeout.tv_sec = wait_seconds ;
timeout.tv_usec = 0 ;
do
{
ret = select ( fd + 1 , NULL ,&write_fdset , NULL , &timeout ) ;
}while(ret < 0 && EINTR == errno )  ;

if ( 0 == ret )
{
ret = -1 ;
errno = ETIMEDOUT ;
}
else if ( 1 == ret )
{
ret = 0 ;
}
}
return ret ;
}

/**
* accept timeout  with the accept function
* fd : socket
* addr : output parameter , return peer addr
* wait_seconds : wait the time of timeout , if 0 = timeout means that it's the normal occassion
* success(not timeout) return the connected socket; when it's timeout return -1 withe errno = ETIMEOUT
*/

int accept_timeout ( int fd , struct sockaddr_in *addr , unsigned int wait_seconds )
{
int ret ;
ret = 0 ;
socklen_t addrlen = sizeof(struct sockaddr_in ) ;
if ( wait_seconds > 0 )
{
fd_set accept_fdset ;
struct timeval timeout ;
FD_ZERO ( &accept_fdset ) ;
FD_SET ( fd , &accept_fdset ) ;
timeout.tv_sec = wait_seconds ;
timeout.tv_usec = 0 ;
do
{
ret = select ( fd + 1 , &accept_fdset , NULL ,NULL , &timeout ) ;
}while(ret < 0 && EINTR == errno ) ;
if ( -1 == ret )
{
return -1 ;
}
else if ( 0 == ret )
{
errno = ETIMEDOUT ;
return -1 ;
}
}
if ( NULL  != addr  )
{
ret = accept ( fd , ( struct sockaddr*) addr , &addrlen ) ;
}
else
{
ret = accept ( fd , NULL , NULL ) ;
}
if ( -1 == ret )
{
ERR_EXIT("accept") ;
}
return ret ;
}

/**
* activate_nonblock
* fd : file descriptor
*/

void activate_nonblock ( int fd )
{
int ret ;
int flags = fcntl ( fd , F_GETFL ) ;		//fcnt1 get the flag of fd.
if ( -1 == flags )
{
ERR_EXIT("fcnt1") ;
}
flags |= O_NONBLOCK ;  				// add non_block model
ret = fcntl ( fd , F_SETFL , flags ) ;
if ( -1 == ret )
{
ERR_EXIT ("fcnt1") ;
}
}

/**
* deactivate_nonblack
* fd : file descriptor
*/

void deactivate_nonblock ( int fd )
{
int ret ;
int flags = fcntl ( fd , F_GETFL ) ;
if ( -1 == flags )
{
ERR_EXIT ("fcnt1") ;
}
flags &= ~ O_NONBLOCK ;       // remove nonblock to the block model
ret = fcntl ( fd , F_SETFL , flags ) ;
if ( -1 == ret )
{
ERR_EXIT ("fcnt1") ;
}
}

/**
* connect_timout -connect
* fd : socket
* addr: the peer address that we need to connect
* wait_seconds : the time which is the timeout, if 0 = wait_seconds it means normal.
* sucdess (it is not timeout ) return 0 ; failed return -1 with errno = ETIMEOUT
*/

int connect_timeout ( int fd , struct sockaddr_in *addr , unsigned int wait_seconds )
{
int ret ;
socklen_t addrlen = sizeof(struct  sockaddr_in );
if ( wait_seconds > 0 )
{
activate_nonblock(fd) ;
}
ret = connect ( fd , ( struct sockaddr*)addr , addrlen ) ;
if ( ret < 0 && EINPROGRESS == errno  )
{
printf ("AAAAAAAAAAAAA\n") ;
fd_set connect_fdset ;
struct timeval timeout ;
FD_ZERO ( &connect_fdset ) ;
FD_SET ( fd , &connect_fdset ) ;
timeout.tv_sec = wait_seconds ;
timeout.tv_usec = 0 ;
do
{
// once connected , the socket is writable
ret = select ( fd + 1 , NULL , &connect_fdset , NULL , &timeout ) ;
}while( ret < 0 && EINTR == errno ) ;
if ( 0 == ret )   // timeout
{
ret = -1 ;
errno = ETIMEDOUT ;
}
else if ( ret < 0 ) // ret < 0 && EINTR != errno which means there is a mistake in socket.
{
return -1 ;
}
else if ( 1 == ret )
{
/* ret = 1 means two occassion , one is the connection is successful. the other
is that the connection has some mistakes.  When there is a mistake in the socket ,
the failed information(but this kind of mistake would not influence select function)
wouldn's save in the errno , we need to use the getsockopt to get it.
*/
printf ("BBBBBBBBBBB\n") ;
int err ;
socklen_t socklen = sizeof(err) ;
int sockopt_ret = getsockopt ( fd , SOL_SOCKET , SO_ERROR , &err , &socklen ) ;
if ( -1 == sockopt_ret )
{
return -1 ;
}
if ( 0 == err )    // no error , the connection is established.
{
printf ("DDDDDDDDDDDDDDD\n") ;
ret = 0 ;
}
else   		  // the socket has a mistake
{
printf ("CCCCCCCCCCCC\n") ;
errno = err ;
ret = -1 ;
}
}
}
if ( wait_seconds > 0 )
{
deactivate_nonblock(fd) ;
}
return ret ;
}

int
main (void)
{
int sock ;
if ( ( sock = socket ( PF_INET , SOCK_STREAM , IPPROTO_TCP ) ) < 0 )
{
ERR_EXIT("socket") ;
}
struct sockaddr_in servaddr ;
memset ( &servaddr , 0 , sizeof(servaddr) ) ;
servaddr.sin_family = PF_INET ;
servaddr.sin_port = htons(5188) ;
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1") ;

int ret = connect_timeout ( sock , &servaddr , 5 ) ;     // timeout = 5
if ( -1 == ret && ETIMEDOUT  == errno )
{
printf ("timeout ...\n") ;
return 1 ;
}
else if ( -1 == ret )
{
ERR_EXIT("connect_timeout") ;
}
struct sockaddr_in localaddr ;
socklen_t addrlen = sizeof(localaddr) ;
if ( getsockname ( sock , ( struct sockaddr*) &localaddr , &addrlen ) < 0 )
{
ERR_EXIT ("getsockname") ;
}
printf ("ip = %s port = %d\n" , inet_ntoa(localaddr.sin_addr) , ntohs(localaddr.sin_port) ) ;
return 0 ;
}


Server :

/************************************************************************
> filename: echocli.c
> Author: ma6174
> Mail: ma6174@163.com
> Created Time: Thu 29 Oct 16:38:57 2015
************************************************************************/
#include <sys/select.h>
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#define ERR_EXIT(m) \
do \
{\
perror(m) ;\
exit(EXIT_FAILURE) ;\
}while(0)

int
main(void)
{
int listenfd ;
if ( (listenfd = socket(PF_INET , SOCK_STREAM , 0 ) ) < 0 )
{
ERR_EXIT("socket") ;
}
struct sockaddr_in servaddr ;
memset ( &servaddr , 0 , sizeof(servaddr) ) ;
servaddr.sin_family = AF_INET ;
servaddr.sin_port = htons(5188) ;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY) ;

int on = 1 ;
if ( setsockopt ( listenfd , SOL_SOCKET , SO_REUSEADDR , &on , sizeof(on) ) < 0 )
{
ERR_EXIT("setsockopt") ;
}
if ( bind ( listenfd , ( struct sockaddr* ) &servaddr , sizeof(servaddr) ) < 0 )
{
ERR_EXIT("bind") ;
}
if ( listen ( listenfd , SOMAXCONN ) < 0 )
{
ERR_EXIT("listen") ;
}
struct sockaddr_in peeraddr ;
socklen_t peerlen ;
peerlen = sizeof(peeraddr) ;
int conn ;
if ( ( conn = accept ( listenfd , ( struct sockaddr* ) &peeraddr , &peerlen ) ) < 0 )
{
ERR_EXIT("accept") ;
}
printf ("ip = %s port = %d\n" , inet_ntoa(peeraddr.sin_addr) , ntohs(peeraddr.sin_port) ) ;
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: