【并发服务器系列】2 select模型
some of the codes are the same with previous article. I just list the different code here .
chat_server.cpp
View Code
#include "chat.h"
extern int sock_server_init(int &listenfd , uint16_t server_port);
void err_quit(const char *error_string)
{
printf("%s\n", error_string);
exit(1);
}
void err_sys(const char *error_string)
{
printf("%s\n", error_string);
}
extern ssize_t p_read_from_p(int clientfd);
extern ssize_t p_write_to_p(int clientfd, const char *msg);
//#define WAIT_TIME_OUT
void sig_chld(int signo)
{
pid_t pid;
int stat;
while( (pid = waitpid(-1, &stat, WNOHANG)) > 0 )
{
printf("client %d terminated \n", pid);
}
return;
}
void chat_server()
{
int listenfd, connfd;
printf("chat server start\n");
void sig_chld(int);
pid_t childpid;
socklen_t clilen;
struct sockaddr_in cliaddr ;
if(sock_server_init(listenfd,(uint16_t) SERVER_PORT) < 0)
{
return ;
}
signal(SIGCHLD, sig_chld);
char buf[200] = {0};
fd_set rset, allset;
int maxfd, maxi, i, nready;
int client[FD_SETSIZE], sockfd;
ssize_t n_have_read;
maxfd = listenfd;
maxi = -1;
for(i = 0; i < FD_SETSIZE; i++)
client[i] = -1;
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
#ifdef WAIT_TIME_OUT
struct timeval timeout;
timeout.tv_sec = 2;
timeout.tv_usec = 500000;
#endif
for( ; ; )
{
rset = allset ;
#ifdef WAIT_TIME_OUT
nready = select( maxfd +1 , &rset , NULL, NULL, &timeout);
#else
nready = select( maxfd +1 , &rset , NULL, NULL, NULL);
#endif
if(nready == 0)
{
printf("select timeout\n");
}
else if(nready < 0)
{
perror("select");
}
else
{
if(FD_ISSET(listenfd, &rset))//new incoming connection
{
int sleep_rand_sec = rand()%4;
printf(" sleep %d ", sleep_rand_sec);
sleep(sleep_rand_sec);
clilen = sizeof(cliaddr);
connfd = accept(listenfd, (SA*)&cliaddr, &clilen);
printf("incoming connection from IP: %s Port: %d\n",
inet_ntop(AF_INET, &cliaddr.sin_addr, buf, sizeof(buf)),
ntohs(cliaddr.sin_port));
for(i= 0; i< FD_SETSIZE; i++)
{
if(client[i] < 0)
{
client[i] = connfd;//save fd to empty pos
break;
}
}//for
if(i == FD_SETSIZE)
err_quit("too many clients");
FD_SET(connfd, &allset);//add new fd to set
//a few trick to avoid read all fdset
if(connfd > maxfd)//compare to mark maxfd for select
maxfd = connfd;
if(i > maxi) //mark max in client[] array
maxi = i;
if(--nready <= 0) //no more fd to read , keep wait in accept
continue;
}//if FD_SSSET
}
//usage of trick to avoid read all fdset
for(i = 0; i <= maxi; i++)
{
if( (sockfd = client[i]) < 0)
continue;//this is not a ready one
if(FD_ISSET(sockfd, &rset))
{
if(( n_have_read = p_read_from_p(sockfd ) ) == 0)
{
//connection closed by other end
printf("close sock %d\n", sockfd);
close(sockfd);
FD_CLR(sockfd, &allset);
client[i] = -1;
//continue;
}
else
{
//printf("n_have_read = %d , client[%d] = %d \n", n_have_read, i, client[i]);
p_write_to_p(sockfd, "hi , this is server");
}
if(--nready <= 0)
break;//no more readable fd to handle keep wait in accetp
}//if FD_ISSET
}//for
}//for
extern int sock_server_init(int &listenfd , uint16_t server_port);
void err_quit(const char *error_string)
{
printf("%s\n", error_string);
exit(1);
}
void err_sys(const char *error_string)
{
printf("%s\n", error_string);
}
extern ssize_t p_read_from_p(int clientfd);
extern ssize_t p_write_to_p(int clientfd, const char *msg);
//#define WAIT_TIME_OUT
void sig_chld(int signo)
{
pid_t pid;
int stat;
while( (pid = waitpid(-1, &stat, WNOHANG)) > 0 )
{
printf("client %d terminated \n", pid);
}
return;
}
void chat_server()
{
int listenfd, connfd;
printf("chat server start\n");
void sig_chld(int);
pid_t childpid;
socklen_t clilen;
struct sockaddr_in cliaddr ;
if(sock_server_init(listenfd,(uint16_t) SERVER_PORT) < 0)
{
return ;
}
signal(SIGCHLD, sig_chld);
char buf[200] = {0};
fd_set rset, allset;
int maxfd, maxi, i, nready;
int client[FD_SETSIZE], sockfd;
ssize_t n_have_read;
maxfd = listenfd;
maxi = -1;
for(i = 0; i < FD_SETSIZE; i++)
client[i] = -1;
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
#ifdef WAIT_TIME_OUT
struct timeval timeout;
timeout.tv_sec = 2;
timeout.tv_usec = 500000;
#endif
for( ; ; )
{
rset = allset ;
#ifdef WAIT_TIME_OUT
nready = select( maxfd +1 , &rset , NULL, NULL, &timeout);
#else
nready = select( maxfd +1 , &rset , NULL, NULL, NULL);
#endif
if(nready == 0)
{
printf("select timeout\n");
}
else if(nready < 0)
{
perror("select");
}
else
{
if(FD_ISSET(listenfd, &rset))//new incoming connection
{
int sleep_rand_sec = rand()%4;
printf(" sleep %d ", sleep_rand_sec);
sleep(sleep_rand_sec);
clilen = sizeof(cliaddr);
connfd = accept(listenfd, (SA*)&cliaddr, &clilen);
printf("incoming connection from IP: %s Port: %d\n",
inet_ntop(AF_INET, &cliaddr.sin_addr, buf, sizeof(buf)),
ntohs(cliaddr.sin_port));
for(i= 0; i< FD_SETSIZE; i++)
{
if(client[i] < 0)
{
client[i] = connfd;//save fd to empty pos
break;
}
}//for
if(i == FD_SETSIZE)
err_quit("too many clients");
FD_SET(connfd, &allset);//add new fd to set
//a few trick to avoid read all fdset
if(connfd > maxfd)//compare to mark maxfd for select
maxfd = connfd;
if(i > maxi) //mark max in client[] array
maxi = i;
if(--nready <= 0) //no more fd to read , keep wait in accept
continue;
}//if FD_SSSET
}
//usage of trick to avoid read all fdset
for(i = 0; i <= maxi; i++)
{
if( (sockfd = client[i]) < 0)
continue;//this is not a ready one
if(FD_ISSET(sockfd, &rset))
{
if(( n_have_read = p_read_from_p(sockfd ) ) == 0)
{
//connection closed by other end
printf("close sock %d\n", sockfd);
close(sockfd);
FD_CLR(sockfd, &allset);
client[i] = -1;
//continue;
}
else
{
//printf("n_have_read = %d , client[%d] = %d \n", n_have_read, i, client[i]);
p_write_to_p(sockfd, "hi , this is server");
}
if(--nready <= 0)
break;//no more readable fd to handle keep wait in accetp
}//if FD_ISSET
}//for
}//for
clientProcess.cpp
View Code
#include "chat.h"
ssize_t p_read_from_p(int clientfd)
{
if(0 == clientfd)
return -1;
Message msg_receive;
ssize_t read_size = 0;//fd read_size
if(( read_size = read(clientfd, &msg_receive.msg_head, sizeof(msg_receive.msg_head))) <= 0)
{
perror("read header");
return read_size;//connection closed by other end
}
if(( read_size += read(clientfd, &msg_receive.msg_content, msg_receive.msg_head.msg_length)) <= 0)
{
perror("read msg");
return read_size;//connection closed by other end
}
printf(" ----> receive msg_content:\t %s \n", msg_receive.msg_content);
fflush(stdout);
return read_size;
}
ssize_t p_write_to_p(int clientfd, const char *msg)
{
size_t slen = strlen(msg);
if(slen > MAX_MSG_LENGTH || 0 == slen)
return -1;
Message msg_send;
msg_send.msg_head.msg_length = slen;
strncpy(msg_send.msg_content , msg, slen);
ssize_t wn = write(clientfd, &msg_send ,sizeof(msg_send.msg_head)+slen );
printf(" write finished msg:\t %s \n",msg );
return wn;
ssize_t p_read_from_p(int clientfd)
{
if(0 == clientfd)
return -1;
Message msg_receive;
ssize_t read_size = 0;//fd read_size
if(( read_size = read(clientfd, &msg_receive.msg_head, sizeof(msg_receive.msg_head))) <= 0)
{
perror("read header");
return read_size;//connection closed by other end
}
if(( read_size += read(clientfd, &msg_receive.msg_content, msg_receive.msg_head.msg_length)) <= 0)
{
perror("read msg");
return read_size;//connection closed by other end
}
printf(" ----> receive msg_content:\t %s \n", msg_receive.msg_content);
fflush(stdout);
return read_size;
}
ssize_t p_write_to_p(int clientfd, const char *msg)
{
size_t slen = strlen(msg);
if(slen > MAX_MSG_LENGTH || 0 == slen)
return -1;
Message msg_send;
msg_send.msg_head.msg_length = slen;
strncpy(msg_send.msg_content , msg, slen);
ssize_t wn = write(clientfd, &msg_send ,sizeof(msg_send.msg_head)+slen );
printf(" write finished msg:\t %s \n",msg );
return wn;
chat_client.cpp
View Code
#include "chat.h"
extern int sock_client_init(const char*ipaddress, uint16_t server_port);
extern ssize_t p_write_to_p(int clientfd, const char *msg);
extern ssize_t p_read_from_p(int clientfd);
void chat_client(const char* linkin_ip)
{
printf("chat client start %s \n", linkin_ip);
int clientfd = sock_client_init(linkin_ip, SERVER_PORT);
if(clientfd < 0 )
{
return ;
}
ssize_t iw = p_write_to_p(clientfd, "hello, this is client");
printf(" iwrite = %d \n", iw);
ssize_t ir = p_read_from_p(clientfd);
printf(" ireadback = %d \n", ir);
if( ir == 0)
printf(" connection close by server\n");
extern int sock_client_init(const char*ipaddress, uint16_t server_port);
extern ssize_t p_write_to_p(int clientfd, const char *msg);
extern ssize_t p_read_from_p(int clientfd);
void chat_client(const char* linkin_ip)
{
printf("chat client start %s \n", linkin_ip);
int clientfd = sock_client_init(linkin_ip, SERVER_PORT);
if(clientfd < 0 )
{
return ;
}
ssize_t iw = p_write_to_p(clientfd, "hello, this is client");
printf(" iwrite = %d \n", iw);
ssize_t ir = p_read_from_p(clientfd);
printf(" ireadback = %d \n", ir);
if( ir == 0)
printf(" connection close by server\n");
usage:
to start a server: ./chat
to start some clients: ./chat localhost & ./chat localhost&./chat localhost & ./chat localhost &
Performance:Testing Machine: Local test ,OS: Fedora 14(Linux 2.6.35) 2 Cores:E3200@2.4GHz, Memory: 2GiB
Result: Handles 100~200 clients per sec