您的位置:首页 > 其它

回射客户端服务器epoll( echo client && server improved by epoll function )

2015-11-11 00:41 477 查看
select :

1.The file descriptors that one process open is limited.

2.FD_SETSIZE

poll : The file descriptors that one process open is limited.

ulimit -n number

The file descriptors that the system run is limited with the memory.

the common points :

The kernel needs to traverse all of the file descriptors until it found the file descriptor with event occurrence. But when the number of file descriptor grows significantly , the efficiency of select function and poll function will decline heavily.So we
use another strategy , that's epoll.

Client :

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

#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)

//ssize_t signed integer   size_t unsigned integer
ssize_t readn ( int fd , void *buf , size_t count )    // encapsulate readn as the function of read
{
size_t nleft = count ;
ssize_t nread ;
char *bufp ;
bufp = ( char *) buf ;
//	printf ("nleft = %d\n" , nleft ) ;
while ( nleft > 0 )
{
//		printf ("nleft = %d\n" , nleft ) ;
nread = read ( fd , bufp , nleft ) ;
//                printf ("nread = %d\n" , nread ) ;
if( nread  < 0 )
{
if ( errno == EINTR )   // interrupted by signal , we don't think this occasion is not right
{
continue ;
}
return -1 ;
}
else if ( 0 == nread )    //peer closed
{
return count - nleft ;
//break ;
}
//		printf ("nreaad = %d\n" , nread ) ;
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 ( errno == EINTR )  // just like the occasion in writen
{
continue ;
}
return -1 ;
}
else if ( 0 == nwritten  ) // if 0 == nread , like nothing happened to write ...
{
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 ;
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 ;
}

int
main ()
{
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 = 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") ;
}
printf ("connected already\n") ;
struct sockaddr_in localaddr ;
socklen_t addrlen = sizeof(localaddr) ;
if ( getsockname ( sock , ( struct sockaddr *) &localaddr , &addrlen ) < 0 )
{
ERR_EXIT ("getsockname") ;
}
printf ("local_ip = %s local_port = %d\n" , inet_ntoa (localaddr.sin_addr ) , ntohs(localaddr.sin_port) ) ;
struct sockaddr_in peeraddr ;
socklen_t peerlen = sizeof(peeraddr) ;
if ( getpeername ( sock , ( struct sockaddr * ) &peeraddr , &peerlen ) < 0 )
{
ERR_EXIT ("getpeername") ;
}
printf ("peer_ip = %s peer_port = %d\n" , inet_ntoa (peeraddr.sin_addr ) , ntohs(peeraddr.sin_port) ) ;
char sendbuf[1024]={0} ;
char recvbuf[1024]={0} ;
memset ( sendbuf , 0 , sizeof(sendbuf) ) ;
memset ( recvbuf , 0 , sizeof(recvbuf) ) ;
int n ;
while( fgets ( sendbuf , sizeof(sendbuf) , stdin ) != NULL )
{
//fgets get the data with '\n' in default
writen ( sock , sendbuf ,strlen(sendbuf) ) ;     // the former 4 bytes and  the real data(n)
int ret = readline ( sock , recvbuf , sizeof(recvbuf) ) ;
if ( -1 == ret )
{
ERR_EXIT ("readline") ;
}
else if ( 0 == ret  )            //may interrupted by signal
{
printf ("clien________ close\n") ;
break ;
}
fputs ( recvbuf , stdout ) ;
memset ( sendbuf , 0 , sizeof(sendbuf) ) ;
memset ( recvbuf , 0 , sizeof(recvbuf) ) ;
}
close ( sock ) ;
return 0 ;
}
Server(write with c++ , cpp file ):

#include <stdio.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/epoll.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <vector>
#include <algorithm>
#include <signal.h>

typedef std::vector<struct epoll_event> EventList ;

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

void activate_nonblock ( int fd )
{
int ret ;
int flags = fcntl (fd , F_GETFL ) ;
if ( -1 == flags )
{
ERR_EXIT("fcntl\n") ;
}
flags |= O_NONBLOCK ;
ret = fcntl(fd , F_SETFL , flags ) ;
if ( -1 == ret )
{
ERR_EXIT ("fcntl") ;
}
}

ssize_t readn ( int fd , void *buf , size_t count )
{
size_t nleft ;
nleft = count ;
ssize_t nread ;
char *bufp = (char*) buf ;
while( nleft > 0 )
{
if ( ( nread = read ( fd , bufp , nleft ) ) < 0 )
{
if ( EINTR == errno )
{
continue ;
}
return -1 ;
}
else if ( 0 == nread )
{
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 = (char*) buf ;
while( nleft > 0 )
{
if ( ( nwritten= write ( fd , bufp , nleft ) ) < 0 )
{
if ( EINTR == errno )
{
continue ;
}
return -1 ;
}
else if ( 0 == nwritten )
{
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 ) ;
if ( -1 == ret && EINTR == errno )
{
continue ;
}
return ret ;
}
}

ssize_t readline ( int sockfd , void *buf , size_t maxline )
{
int ret ;
int nread ;
char *bufp = ( char * ) buf ;
int nleft ;
nleft = maxline ;
while ( 1 )
{
ret = recv_peek ( sockfd , bufp , nleft ) ;
if ( ret < 0 )
{
return ret ;
}
else if ( 0 == ret )
{
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 )
{
exit(EXIT_FAILURE ) ;
}
nleft -= nread ;
bufp += nread ;
}
return -1 ;
}

void handle_sigchld ( int sig )
{
while( waitpid ( -1 , NULL , WNOHANG ) > 0 )
;
}

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

int
main (void)
{
int count ;
count = 0 ;
signal ( SIGPIPE , handle_sigpipe ) ;
signal ( SIGCHLD , handle_sigchld ) ;
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 = 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") ;
}
std::vector<int>clients ;
int epollfd ;
epollfd = epoll_create1(EPOLL_CLOEXEC) ;
//epollfd = epoll_create1(0) ;
//EPOLL_CLOEXEC when the process is replaced , the file descriptor will be closed.

struct epoll_event event ;
event.data.fd = listenfd ;
event.events = EPOLLIN | EPOLLET ;
//EPOLLET edge triggered flip-flop,the default(EPOLLLT) is master-slave flip flop.
epoll_ctl ( epollfd , EPOLL_CTL_ADD , listenfd , &event ) ;

EventList events(16) ;
struct sockaddr_in peeraddr ;
socklen_t peerlen ;
int conn ;
int nready ;
while ( 1 )
{
nready = epoll_wait ( epollfd , &(*events.begin()) , static_cast<int>(events.size()) , -1 ) ;
// -1 means wait all the time until there is an event .
if ( -1 == nready )
{
if ( EINTR == errno )
{
continue ;
}
ERR_EXIT("epoll_wait") ;
}
if ( 0 == nready )
{
continue ;
}
if ( ( size_t ) nready == events.size() ) // not big enough , resize ...
{
events.resize(events.size()*2) ;
}
int i ;
for ( i = 0 ; i < nready ; i ++ )
{
if ( events[i].data.fd == listenfd )
{
struct sockaddr_in peeraddr ;
socklen_t peerlen ;
peerlen = sizeof(peeraddr) ;
conn = accept ( listenfd , ( struct sockaddr*) &peeraddr , &peerlen ) ;
//conn = accept ( listenfd , NULL , NULL ) ;
if ( -1 == conn )
{
ERR_EXIT("accept\n ") ;
}
printf("ip = %s port = %d\n" , inet_ntoa(peeraddr.sin_addr) , ntohs(peeraddr.sin_port) ) ;
printf ("count = %d\n" , ++count) ;
clients.push_back(conn) ;
activate_nonblock(conn) ;
event.data.fd =  conn ;
event.events = EPOLLIN|EPOLLET ;
epoll_ctl ( epollfd , EPOLL_CTL_ADD , conn , &event ) ;
}
else if ( events[i].events & EPOLLIN )
{
conn = events[i].data.fd ;
if ( conn < 0 )
{
continue ;
}
char recvbuf[1024] = {0} ;
int ret = readline(conn , recvbuf , 1024) ;
if ( -1 == ret )
{
ERR_EXIT("readline") ;
}
if ( 0 == ret )
{
printf ("client close\n") ;
close(conn) ;
event = events[i] ;
epoll_ctl ( epollfd , EPOLL_CTL_DEL , conn , &event ) ;
clients.erase(std::remove(clients.begin() , clients.end() , conn) , clients.end()) ;
}
fputs ( recvbuf , stdout ) ;
writen(conn , recvbuf , strlen(recvbuf)) ;
}
}
}
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: