select()函数允许进程指示内核等待多个事件(文件描述符)中的任何一个发生,并只在有一个或多个事件发生或经历一段指定时间后才唤醒它,然后接下来判断究竟是哪个文件描述符发生了事件并进行相应的处理。
#include
#include
#include
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
void FD_CLR(int fd, fd_set *set); //用来删除一个已经没有使用的文件描述符fd
int FD_ISSET(int fd, fd_set *set); //判断文件描述是否在集合中
void FD_SET(int fd, fd_set *set); //将文件描述符fd加入的select的文件描述符集合
void FD_ZERO(fd_set *set); //将select的文件描述符集合清空
/*可以用来设置select的超时时间*/
struct timeval {
long tv_sec; //秒
long tv_usec; //毫秒
/linux/posix_types.h:
#define __FD_SETSIZE 1024
1.select能监听的文件描述符个数受限于FD_SETSIZE,一般为1024,单纯改变进程打开的文件描述符个数并不能改变select监听文件个数,解决1024以下客户端时使用select是很合适的,但如果链接客户端过多,select采用的是轮询模型,会大大降低服务器响应效率,不应在select上投入更多精力。
2.每次调⽤用select,都需要把fd集合从⽤用户态拷贝到内核态,这个开销在fd很多时会很⼤大。
3.同时每次调⽤用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很⼤大。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
#define MSG_NUM 1024
void print_usage(char *progname)
{
printf("%s usage: \n", progname);
printf("-p(--LISTEN_PORT): sepcify server port.\n");
printf("-h(--Help): print this help information.\n");
return ;
}
static inline void msleep(unsigned long ms);
int main(int argc,char **argv)
{
int sockfd = -1;
int clifd ;
int rv =-1;
int LISTEN_PORT ;
int rw;
int on =1;
int i,j;
int found;
int fds_array[1024];
int maxfd=0;
fd_set rdset;
int f;
char buf[MSG_NUM];
struct sockaddr_in servaddr;
struct sockaddr_in cliaddr;
pthread_t tid;
socklen_t cli_len=sizeof(struct sockaddr);
struct option longopts[] = {
{
"help", no_argument, NULL, 'h'},
{
"LISTEN_PORT", required_argument, NULL, 'P'},
{
0, 0, 0, 0}
};
while( (rw=getopt_long(argc, argv, "p:h", longopts, NULL)) != -1 )
{
switch(rw)
{
case 'p':
LISTEN_PORT=atoi(optarg);
break;
case 'h':
print_usage(argv[0]);
return 0;
}
}
if( !LISTEN_PORT )
{
print_usage(argv[0]);
return 0;
}
sockfd=socket(AF_INET, SOCK_STREAM,0);
if(sockfd<0)
{
printf("Create socket failure:%s\n",strerror(errno));
return 0;
}
printf("Create socket[%d] successfully!\n",sockfd);
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_port = htons(LISTEN_PORT);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr))<0)
{
printf("Bind socket failure:%s\n ",strerror(errno));
return -1;
}
printf("socket[%d] bind on port[%d] for all IP address ok\n",sockfd,LISTEN_PORT);
listen(sockfd,13);
printf("Start to listen on port [%d]\n", LISTEN_PORT);
for(i=0; i<ARRAY_SIZE(fds_array) ; i++)
{
fds_array[i]=-1;
}
fds_array[0] = sockfd;
for ( ; ; )
{
FD_ZERO(&rdset);
for(i=0; i<ARRAY_SIZE(fds_array) ; i++)
{
if( fds_array[i] < 0 )
continue;
maxfd = fds_array[i]>maxfd ? fds_array[i] : maxfd;
FD_SET(fds_array[i], &rdset);
}
rv = select(maxfd+1, &rdset, NULL, NULL, NULL);
if(rv < 0)
{
printf("select failure: %s\n", strerror(errno));
break;
}
else if(rv == 0)
{
printf("select get timeout\n");
continue;
}
if ( FD_ISSET(sockfd, &rdset) )
{
printf("Start accept new client incoming...\n");
if( (clifd=accept(sockfd, (struct sockaddr *)NULL, NULL)) < 0)
{
printf("accept new client failure: %s\n", strerror(errno));
continue;
}
found = 0;
for(i=0; i<ARRAY_SIZE(fds_array) ; i++)
{
if( fds_array[i] < 0 )
{
printf("accept new client[%d] and add it into array\n", clifd );
fds_array[i] = clifd;
found = 1;
break;
}
}
if( !found )
{
printf("accept new client[%d] but full, so refuse it\n", clifd);
close(clifd);
}
}
else
{
for(i=0; i<ARRAY_SIZE(fds_array); i++)
{
if( fds_array[i]<0 || !FD_ISSET(fds_array[i], &rdset) )
continue;
if( (rv=read(fds_array[i], buf, sizeof(buf))) <= 0)
{
printf("socket[%d] read failure or get disconncet.\n", fds_array[i]);
close(fds_array[i]);
fds_array[i] = -1;
}
else
{
printf("socket[%d] read get %d bytes data\n", fds_array[i], rv);
for(j=0; j<rv; j++)
buf[j]=toupper(buf[j]);
if( write(fds_array[i], buf, rv) < 0 )
{
printf("socket[%d] write failure: %s\n", fds_array[i], strerror(errno));
close(fds_array[i]);
fds_array[i] = -1;
}
}
}
}
}
close(sockfd);
return 0;
}
static inline void msleep(unsigned long ms)
{
struct timeval tv;
tv.tv_sec = ms/1000;
tv.tv_usec = (ms%1000)*1000;
select(0, NULL, NULL, NULL, &tv);
}