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:超时时间,主要分为三种

  1. NULL:永远等待下去,仅在有一个描述字准备好I/O时才返回;
  2. 0:立即返回,仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生;
  3. 特定的时间值: 如果在指定的时间段里没有事件发生,select将超时返回;
struct timeval
{
__time_t tv_sec;        /* Seconds. */
__suseconds_t tv_usec;  /* Microseconds. */
};

return: 有三种情况

  1. 返回0表示超时了;
  2. 返回-1,表示出错了;
  3. 返回一个大于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\n", 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\n", 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\n", errno );
46         close( listenfd );
47     }
48 
49     char remote_addr[INET_ADDRSTRLEN];
50     printf( "connected with ip: %s and port: %d\n", 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, '\0', sizeof( buf ) );
64         FD_SET( connfd, &read_fds );
65         FD_SET( connfd, &exception_fds );
66 
67         ret = select( connfd + 1, &read_fds, NULL, &exception_fds, NULL );
68         printf( "select one\n" );
69         if ( ret < 0 )
70         {
71                 printf( "selection failure\n" );
72                 break;
73         }
74 
75         if ( FD_ISSET( connfd, &read_fds ) )
76         {
77             ret = recv( connfd, buf, sizeof( buf )-1, 0 );
78             if( ret <= 0 )
79             {
80                 break;
81             }
82             printf( "get %d bytes of normal data: %s\n", ret, buf );
83         }
84         else if( FD_ISSET( connfd, &exception_fds ) )
85         {
86             ret = recv( connfd, buf, sizeof( buf )-1, MSG_OOB );
87             if( ret <= 0 )
88             {
89                 break;
90             }
91             printf( "get %d bytes of oob data: %s\n", ret, buf );
92         }
93 
94     }
95 
96     close( connfd );
97     close( listenfd );
98     return 0;
99 }
View Code

相关文章:

  • 2021-12-27
  • 2022-12-23
  • 2021-07-05
  • 2021-04-26
  • 2021-12-13
  • 2022-12-23
  • 2022-01-07
  • 2021-05-24
猜你喜欢
  • 2021-12-27
  • 2021-10-22
  • 2021-11-26
  • 2022-12-23
  • 2021-12-28
  • 2021-10-14
相关资源
相似解决方案