通过poll修改最大并发数(the maximum concurrent connection improved by poll )

When we use select function to realise concurrent server , the times of concurrent connection is limited by two sides.

(1) One is that the max count of a process can open is limited , but we can fix that by adjusting kernel parameter which is simple. 

(2) The other is that when we use select method we were limited by the volume set of fd_set (FD_SETSIZE) , if we want to break this limitation , we need to recompile kernel which make our work really complicated.

In order to solve this problem , we poll function to realise multi-concurrent connection instead of select. 

Client :

/************************************************************************
 >file name : echocli.c
    > Author: ma6174
    > Mail: ma6174@163.com 
    > Created Time: Thu 29 Oct 16:38:57 2015
 ************************************************************************/
/*
When we test the max count of conncurrent connection , we need to adjust the kernal 
parameter with the client's and server's side. 
root#: ulimit -n 2048  ( client )
root#: ulimit -n 2048  ( server ) 
*/


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

#define ERR_EXIT(m) \
	do \
	{\
		perror(m) ;\
		exit(EXIT_FAILURE) ;\
	}while(0) 



int 
main () 
{
	int n ;
	n = 0 ;
	while(1) 
	{
		int sock ;
		if (( sock= socket ( PF_INET , SOCK_STREAM , IPPROTO_TCP )) < 0 ) 
		{
			sleep(4) ;
			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) ;
		servaddr.sin_addr.s_addr = inet_addr("127.0.0.1") ;
		//inet_aton("127.0.0.1" , &servaddr.sin_addr) ;
 		if ( connect ( sock , ( struct sockaddr * )& servaddr, sizeof(servaddr )) < 0 )
		{
			ERR_EXIT("connet") ;
		}
		struct sockaddr_in localaddr ;
		socklen_t addrlen = sizeof(localaddr) ;
		if ( getsockname ( sock , ( struct sockaddr *) &localaddr , &addrlen ) < 0 )
		{
			ERR_EXIT ("getsockname") ;
		}
		printf("n = %d\n" , ++n  ) ;
		printf ("local_ip = %s local_port = %d\n" , inet_ntoa (localaddr.sin_addr ) , ntohs(localaddr.sin_port) ) ;
	//	close ( sock ) ; 
	}
	return 0 ;
}

Server :

/************************************************************************
    > filename: echoserv2.c
    > Author: ma6174
    > Mail: ma6174@163.com 
    > Created Time: Thu 29 Oct 16:38:57 2015
 ************************************************************************/
#include <poll.h>
#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) 


//ssize_t the signed integer , size_t the unsigned integer 
ssize_t readn ( int fd , void *buf , size_t count )   //encapsulate like read function 
{
	size_t nleft = count ;
	ssize_t nread ;
	char *bufp ;
	bufp = ( char *) buf ;
	while ( nleft > 0 ) 
	{
		//nread = read ( fd , bufp , nleft ) ;
		//printf ("nread = %d\n" , nread ) ;
		if ( (nread = read ( fd , bufp , nleft )) < 0  ) 
		{
			if ( EINTR  == errno ) // interrupted by the signal , we don't think this occasion is a mistake 
			{
				continue ;
			}
			return -1 ;  		//failure 
		}   
		else if ( 0 == nread )  // peer close 
		{
			return count - nleft ; 	
		}	
		bufp += nread ;
		nleft -= nread ;
	}
	return count ;
}


ssize_t writen ( int fd ,const void *buf , size_t count ) 
{
	size_t nleft = count ;
	ssize_t nwritten ;
	char * bufp ;
	bufp = (char*) buf ;
	while ( nleft > 0 ) 
	{
		if ( ( nwritten = write ( fd , bufp , nleft ) ) < 0 ) 
		{
			if ( EINTR == errno ) 
			{
				continue ;	
			}
			return -1 ;
		}
		else if ( 0 == nwritten )    // like nothing happened to write function   
		{
			continue ;	
		}
		bufp += nwritten ;
		nleft -= nwritten ;
	}
	return count ;
}

		

ssize_t recv_peek ( int sockfd , void *buf , size_t len ) 
{
	while ( 1 ) 
	{
		int ret = recv ( sockfd , buf , len , MSG_PEEK ) ;   
//only let buf read the data from sockfd but not remove the data from that sockfd(socket) 
//in comparison with read function it receive the data and remove the data in the socket 
		if ( -1 == ret && EINTR == errno ) 
		{
			continue ;			//interrupted by signal 
		}
		return ret ;
	}
}

                                                                                                                                                                                                                                                      
ssize_t readline ( int sockfd , void *buf  , size_t maxline ) 
{
	int ret ;
	int nread ;
	char *bufp ;
	bufp = (char*) buf ;
	//printf("sockfd = %d buf =%s \n" , sockfd , bufp ) ;
	int nleft ;
	nleft = maxline ;
	while (1 ) 
	{
		ret = recv_peek ( sockfd, bufp , nleft ) ;
		if ( ret < 0 )    //failure 
		{
			return ret ;
		}
		else if ( 0 == ret )		// peer closed  
		{
			return ret ;
		}
		nread = ret ;
		int i ;
		for ( i = 0 ; i < nread ; i ++ ) 
		{
			if ( '\n' ==  bufp[i]) 
			{
				ret = readn (sockfd,bufp , i+1) ;
				if ( ret != i + 1 ) 
				{
					exit(EXIT_FAILURE) ;
				}
				return ret ;
			}
		}
		if ( nread > nleft )   // the data that we read(nread) can't be more than the real data in the socket 
		{
			exit ( EXIT_FAILURE ) ;
		}
		nleft -= nread ;
		ret = readn ( sockfd , bufp , nread ) ;  // read n characters from the socket ( don't contain '\n') 
		if ( ret != nread ) 
		{
			exit(EXIT_FAILURE ) ;	
		}
		bufp += nread ;
	}
	return -1 ;
}


void echo_serv ( int conn ) 
{
	 char recvbuf[1024] ;
	 while(1) 
	 {
		 memset ( recvbuf , 0 , sizeof(recvbuf) ) ;
		 int ret = readline ( conn , recvbuf , sizeof(recvbuf) ) ;
		 if ( -1 == ret ) 
		 {
			 ERR_EXIT("readline") ;
		 }
		if ( 0 == ret ) 
		{
			//	ERR_EXIT ("client close\n") ;
			printf("client close\n") ;
			break ;
		}
		fputs ( recvbuf , stdout ) ;
		writen ( conn , recvbuf , strlen(recvbuf) ) ; 
	 }
}


void handle_sigchld ( int sig ) 
{
//	wait ( NULL ) ; 	//call wait function to catch the process of the son 
/*ther will be a problem to call wait if there many sons' processes , wait function can 
not wait all the sons' processes to quit. Another saying is that wait funciton can not 
guarantee that there is clear of zombie processes when many sons's processes exist. 
wait function only wait for the first son process to quit ,then wait will quit immediately.
In order to improve this performance , we use waitpid() to change. 
*/
//	static i = 0 ;
//	printf ("i = %d\n",++i ) ;
	
	while ( waitpid(-1,NULL,WNOHANG) > 0 ) 
		 ;	
	/*-1 means all of the son process will quit,WNOHANG means wait no hang
	 no hang means when there is no son process , waitpid will return -1 :*/
}


void handle_sigpipe( int sig ) 
{
	printf ("recv a sig = %d\n" , sig ) ;
}


int 
main () 
{

	signal ( SIGPIPE , handle_sigpipe ) ;     // catch the SIGPIPE signal when the peer client close
	signal ( SIGCHLD , handle_sigchld ) ;
//	signal ( SIGCHLD , SIG_IGN ) ; 
  /* neglect the signal of SIGCHLD to avoid zombie process which happened to
 the server when the client quit , but the server still keeps listening.*/ 
	int listenfd ;
	if (( listenfd = 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  = htonl(INADDR_ANY) ;		//INTADDR_ANY == 0

	//other two means to change the host address to network address  
	//servaddr.sin_addr.s_addr = inet_addr("127.0.0.1") ;   
	//inet_aton("127.0.0.1" , &servaddr.sin_addr) ;
	
	//set out the bind has already used by SO_REUSEADDR 
	int on = 1 ;
	int opt ;
	if (( opt = setsockopt (listenfd ,SOL_SOCKET , SO_REUSEADDR, &on , sizeof(on) )) < 0 )
	{
		ERR_EXIT("setsocketopt") ;
	}
	if ( bind ( listenfd , (struct sockaddr * ) &servaddr  , sizeof(servaddr )) < 0 )  
	{	
		ERR_EXIT("bind") ;
	}
	if ( listen ( listenfd , SOMAXCONN) < 0 ) 
	{
		ERR_EXIT("listen") ;
	}
	struct pollfd client[2048] ;  		// poll  
	int i ;
	for ( i = 0 ; i < 2048 ; i ++ ) 
	{
		client[i].fd  = -1 ;           	//-1 means free 
	}
	int nready ;
	/*
	int maxfd ;
	maxfd = listenfd + 1 ;
	fd_set rset ;
	fd_set allset ;
	FD_ZERO(&rset) ;
	FD_ZERO(&allset) ;
	FD_SET ( listenfd , &allset ) ;
	*/
	struct sockaddr_in peeraddr ;
	socklen_t peerlen = sizeof(peeraddr) ;
	int count ;				//calculate the times of connection.
	count = 0 ;
	int conn ;
	client[0].events = POLLIN ;      	 // POLL_IN means writeable event ;
	client[0].fd = listenfd ;
	int maxIndex ;				// the max position which is not free 
	maxIndex = 0 ;  
	while(1)  
	{
		//rset = allset ;
		nready = poll ( client , maxIndex + 1 , 1 ) ; 			//-1 means wait for all the time. 
		//printf ("nread = %d\n" , nready ) ;
		//nready = select ( maxfd + 1 , &rset , NULL , NULL , NULL ) ;
		if ( -1 == nready ) 
		{
			if ( EINTR == errno )   // interrupted by signal .
			{
				continue ;	
			}
			ERR_EXIT("select") ;
		}
		/*
		if (nready) 
		{
			printf("nread = %d\n", nready) ;
		}
		*/
		if ( 0 == nready )	 //  timeout 
		{
			continue ;
		}
		if ( client[0].revents & POLLIN ) 	//listening socket creats an writeable event 
		{
			//printf ("output \n\n") ;
			socklen_t peerlen = sizeof(peeraddr) ;
			conn = accept ( listenfd , (struct sockaddr*) &peeraddr , &peerlen ) ;
			if ( -1 == conn ) 
			{
				ERR_EXIT("accept") ;
			}
			for ( i = 0 ; i < 2048 ; i ++ ) 
			{
				if ( client[i].fd < 0 ) 
				{
					client[i].fd = conn ;
					client[i].events = POLLIN ;	
					if ( i > maxIndex ) 
					{
						maxIndex = i ;
					}
					break ;
				}
			}
			if ( 2048  == i ) 
			{
				fprintf ( stderr, "too many clients\n") ;
				exit (EXIT_FAILURE) ;	
			}
			//int count ;
			//count = 0 ;
			printf("count = %d\n" , ++count ) ;
			printf ("ip = %s port = %d\n" , inet_ntoa(peeraddr.sin_addr) , ntohs(peeraddr.sin_port) ) ;
			//client[i].events = POLLIN ;	
			if ( --nready <= 0  )        // all the monitoring event were cleared out. 
			{
				continue ;	
			}
		}
		for ( i = 1 ; i <= maxIndex ;  i ++ )		//connected socket creat a writeable event 
		{
			conn = client[i].fd ;
			if ( -1 == conn ) 
			{
				continue ;	
			}
			if ( client[i].revents & (POLLIN | POLLERR) ) 
			{
				//printf("output\n") ;
				
				char recvbuf[1024] = {0} ;
				int ret = readline ( conn , recvbuf , 1024 ) ;
				if ( -1 == ret ) 
				{
					ERR_EXIT("readline") ;
				}
				if ( 0 == ret ) 
				{
					printf ("client close\n") ;
					client[i].fd = -1 ;
					close (conn ) ; // this is a bug which we missed before 
				}
				//printf("ret = %d\n", ret ) ;
				fputs ( recvbuf , stdout ) ;
				//	sleep(4) ;
				writen ( conn , recvbuf , strlen(recvbuf) ) ;
				if ( -- nready <= 0 ) 
				{
					break ; 
				}
			}
		}
	}		  
	return 0 ;
}

When we change the parameter of both sides ( ulimit -n 2048) , we found that the max concurrent connection of server is 2044 ( 1 - 2044 )  , because we have stdin input , stdin output , stdin error and listenfd( the listening socket), in comparison with server , the client's number is 2045 , because the client don't need to listen.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值