select系统调用
#include <sys/select.h> int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
nfds:是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1
readfds:对应可读的文件符集合,是我们关心的,是否可以从这些文件中读取数据的集合,
若有大于等于一个可读文件,则select会返回大于0的值。若无,则根据timeout判断。
writefds: 对应可写的文件符集合。
exceptfds:对应异常的文件符集合。
fd_set结构如下:可以看出容量是有限的,最大1024,一般通过以下来操作
- FD_CLR(inr fd,fd_set* set):用来清除文件描述符集合set中相关fd的位
- FD_ISSET(int fd,fd_set *set):用来测试文件描述符集合set中相关fd的位是否为真
- FD_SET(int fd,fd_set*set):用来设置文件描述符集合set中相关fd的位
- FD_ZERO(fd_set *set):用来清除文件描述符集合set的全部位
#define __FD_SETSIZE 1024 /* fd_set for select and pselect. */ typedef struct { /* XPG4.2 requires this member name. Otherwise avoid the name from the global namespace. */ #ifdef __USE_XOPEN __fd_mask fds_bits[__FD_SETSIZE / __NFDBITS]; # define __FDS_BITS(set) ((set)->fds_bits) #else __fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS]; # define __FDS_BITS(set) ((set)->__fds_bits) #endif
timeout:超时时间,主要分为三种
- NULL:永远等待下去,仅在有一个描述字准备好I/O时才返回;
- 0:立即返回,仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生;
- 特定的时间值: 如果在指定的时间段里没有事件发生,select将超时返回;
struct timeval { __time_t tv_sec; /* Seconds. */ __suseconds_t tv_usec; /* Microseconds. */ };
return: 有三种情况
- 返回0表示超时了;
- 返回-1,表示出错了;
- 返回一个大于0的数,表示文件描述符状态改变的个数;
demo:
1 #include <sys/types.h> 2 #include <sys/socket.h> 3 #include <netinet/in.h> 4 #include <arpa/inet.h> 5 #include <assert.h> 6 #include <stdio.h> 7 #include <unistd.h> 8 #include <errno.h> 9 #include <string.h> 10 #include <fcntl.h> 11 #include <stdlib.h> 12 13 int main( int argc, char* argv[] ) 14 { 15 if( argc <= 2 ) 16 { 17 printf( "usage: %s ip_address port_number ", basename( argv[0] ) ); 18 return 1; 19 } 20 const char* ip = argv[1]; 21 int port = atoi( argv[2] ); 22 printf( "ip is %s and port is %d ", ip, port ); 23 24 int ret = 0; 25 struct sockaddr_in address; 26 bzero( &address, sizeof( address ) ); 27 address.sin_family = AF_INET; 28 inet_pton( AF_INET, ip, &address.sin_addr ); 29 address.sin_port = htons( port ); 30 31 int listenfd = socket( PF_INET, SOCK_STREAM, 0 ); 32 assert( listenfd >= 0 ); 33 34 ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) ); 35 assert( ret != -1 ); 36 37 ret = listen( listenfd, 5 ); 38 assert( ret != -1 ); 39 40 struct sockaddr_in client_address; 41 socklen_t client_addrlength = sizeof( client_address ); 42 int connfd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength ); 43 if ( connfd < 0 ) 44 { 45 printf( "errno is: %d ", errno ); 46 close( listenfd ); 47 } 48 49 char remote_addr[INET_ADDRSTRLEN]; 50 printf( "connected with ip: %s and port: %d ", inet_ntop( AF_INET, &client_address.sin_addr, remote_addr, INET_ADDRSTRLEN ), ntohs( client_address.sin_port ) ); 51 52 char buf[1024]; 53 fd_set read_fds; 54 fd_set exception_fds; 55 56 FD_ZERO( &read_fds ); 57 FD_ZERO( &exception_fds ); 58 59 int nReuseAddr = 1; 60 setsockopt( connfd, SOL_SOCKET, SO_OOBINLINE, &nReuseAddr, sizeof( nReuseAddr ) ); 61 while( 1 ) 62 { 63 memset( buf, '