select能监听的文件描述符个数受限于FD_SETSIZE,一般为1024,单纯改变进程打开的文件描述符个数并不能改变select监听文件个数
解决1024以下客户端时使用select是很合适的,但如果链接客户端过多,select采用的是轮询模型,会大大降低服务器响应效率,不应在select上投入更多精力
声明
# include <sys/select.h>
# include <sys/time.h>
# include <sys/types.h>
# include <unistd.h>
int select ( int nfds, fd_set * readfds, fd_set * writefds,
fd_set * exceptfds, struct timeval * timeout) ;
void FD_CLR ( int fd, fd_set * set) ;
int FD_ISSET ( int fd, fd_set * set) ;
void FD_SET ( int fd, fd_set * set) ;
void FD_ZERO ( fd_set * set) ;
代码实现
server
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <string.h>
# include <arpa/inet.h>
# include <ctype.h>
# include "wrap.h"
# define SERV_PORT 6666
int main ( int argc, char * argv[ ] )
{
int i, j, n, maxi;
int nready, client[ FD_SETSIZE] ;
int maxfd, listenfd, connfd, sockfd;
char buf[ BUFSIZ] , str[ INET_ADDRSTRLEN] ;
struct sockaddr_in clie_addr, serv_addr;
socklen_t clie_addr_len;
fd_set rset, allset;
listenfd = Socket ( AF_INET, SOCK_STREAM, 0 ) ;
int opt = 1 ;
setsockopt ( listenfd, SOL_SOCKET, SO_REUSEADDR, & opt, sizeof ( opt) ) ;
bzero ( & serv_addr, sizeof ( serv_addr) ) ;
serv_addr. sin_family= AF_INET;
serv_addr. sin_addr. s_addr = htonl ( INADDR_ANY) ;
serv_addr. sin_port= htons ( SERV_PORT) ;
Bind ( listenfd, ( struct sockaddr * ) & serv_addr, sizeof ( serv_addr) ) ;
Listen ( listenfd, 128 ) ;
maxfd = listenfd;
maxi = - 1 ;
for ( i = 0 ; i < FD_SETSIZE; i++ )
client[ i] = - 1 ;
FD_ZERO ( & allset) ;
FD_SET ( listenfd, & allset) ;
while ( 1 ) {
rset = allset;
nready = select ( maxfd+ 1 , & rset, NULL , NULL , NULL ) ;
if ( nready < 0 )
perr_exit ( "select error" ) ;
if ( FD_ISSET ( listenfd, & rset) ) {
clie_addr_len = sizeof ( clie_addr) ;
connfd = Accept ( listenfd, ( struct sockaddr * ) & clie_addr, & clie_addr_len) ;
printf ( "received from %s at PORT %d\n" ,
inet_ntop ( AF_INET, & clie_addr. sin_addr, str, sizeof ( str) ) ,
ntohs ( clie_addr. sin_port) ) ;
for ( i = 0 ; i < FD_SETSIZE; i++ )
if ( client[ i] < 0 ) {
client[ i] = connfd;
break ;
}
if ( i == FD_SETSIZE) {
fputs ( "too many clients\n" , stderr ) ;
exit ( 1 ) ;
}
FD_SET ( connfd, & allset) ;
if ( connfd > maxfd)
maxfd = connfd;
if ( i > maxi)
maxi = i;
if ( -- nready == 0 )
continue ;
}
for ( i = 0 ; i <= maxi; i++ ) {
if ( ( sockfd = client[ i] ) < 0 )
continue ;
if ( FD_ISSET ( sockfd, & rset) ) {
if ( ( n = Read ( sockfd, buf, sizeof ( buf) ) ) == 0 ) {
Close ( sockfd) ;
FD_CLR ( sockfd, & allset) ;
client[ i] = - 1 ;
} else if ( n > 0 ) {
for ( j = 0 ; j < n; j++ )
buf[ j] = toupper ( buf[ j] ) ;
Write ( sockfd, buf, n) ;
Write ( STDOUT_FILENO, buf, n) ;
}
if ( -- nready == 0 )
break ;
}
}
}
Close ( listenfd) ;
return 0 ;
}
client
# include <stdio.h>
# include <string.h>
# include <unistd.h>
# include <arpa/inet.h>
# include <netinet/in.h>
# include "wrap.h"
# define MAXLINE 80
# define SERV_PORT 6666
int main ( int argc, char * argv[ ] )
{
struct sockaddr_in servaddr;
char buf[ MAXLINE] ;
int sockfd, n;
if ( argc != 2 )
printf ( "./client IP\n" ) ;
sockfd = Socket ( AF_INET, SOCK_STREAM, 0 ) ;
bzero ( & servaddr, sizeof ( servaddr) ) ;
servaddr. sin_family = AF_INET;
inet_pton ( AF_INET, argv[ 1 ] , & servaddr. sin_addr) ;
servaddr. sin_port = htons ( SERV_PORT) ;
Connect ( sockfd, ( struct sockaddr * ) & servaddr, sizeof ( servaddr) ) ;
printf ( "------------connect ok----------------\n" ) ;
while ( fgets ( buf, MAXLINE, stdin ) != NULL ) {
Write ( sockfd, buf, strlen ( buf) ) ;
n = Read ( sockfd, buf, MAXLINE) ;
if ( n == 0 ) {
printf ( "the other side has been closed.\n" ) ;
break ;
}
else
Write ( STDOUT_FILENO, buf, n) ;
}
Close ( sockfd) ;
return 0 ;
}