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

来源:互联网 发布:boost高并发网络框架 编辑:程序博客网 时间:2024/05/18 00:01

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 modelret = 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 writableret = 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 ;}


0 0
原创粉丝点击