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

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 ;
}
	


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值