Linux培训
达内IT学院
400-996-5531
select函数:
参数含义:
nfds:一个整型变量,它比所有文件描述符集合中的文件描述符的最大值大1。使用select的时候,必须计算最大值的文件描述符的值,将值通过nfds传入。
readfds:这个文件描述符集合监视文件集中的任何文件是否有数据可读,当select()返回的时候,readfds将清除其中不可读的文件描述符,只留下可读的文件描述符,即可以被recv()、read()等进行读操作。
writefds:这个文件描述符集合监视文件集中的任何文件是否有数据可写,当select()返回的时候,readfds将清除其中不可写的文件描述符,只留下可写的文件描述符,即可以被send()、write()等进行读操作。
exceptfds:这个文件集合将监视文件中的任何文件是否发生错误,其实,它还能用于监视带外数据OOB,带外数据使用MSG_OOB标志发送到套接字上。当select()返回时,readfds将清除其中的其他文件描述符,只留下可读的OOB数据。
timeout:设置在select()所监视的文件集合中的事件没有发生时,最长的等待时间,当超过这个时间时,函数返回。当超时返回为NULL时,表示阻塞操作,会一直等待,直到某个监视的文件集中的某个文件描述符符合返回条件。当timeout的值为0时,select()会立即返回。
sigmask:信号
返回值:
当返回大于0的正值:监视的文件集合中的文件描述符符合上述要求。
当等于0时:超时。
当为-1时:发生错误
struct timeval结构:
struct timeval
{
time_t tv_sec; //秒
long tv_usec; // 微秒,即1/1000000s
}
另外,还有4个宏操作文件描述符的集合:
FD_ZERO():清理文件描述符集合;
FD_SET():向某个文件描述符集合中加入文件描述符;
FD_CLR():从某个文件描述符集合中取某个文件描述符;
FD_ISSET():测试某个文件描述符是否为某个集合中的一员。
注:文件描述符的集合存在最大的限制,其最大值为FD_SETSIZE,当超出最大值时,发生不可预料的事。同时,可以修改这个值,但是监视集合的效率会降低,因为select()轮询的线性的,更加牛B的的函数,请查看epoll:epoll没有最大并发连接的限制,上限是最大可以打开文件的数目,这个数字一般远大于2048, 一般来说这个数目和系统内存关系很大。最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,epoll的效率就会远远高于select和poll。在内存拷贝上,epoll在这点上使用了“共享内存”,这个内存拷贝也省略了----epoll的相关函数白天写了,现在睡觉。
附加:使用select()写的IO复用循环服务器模型的例子、
复制代码
1 #include <sys/types.h>
2 #include <sys/socket.h>
3 #include <netinet/in.h>
4 #include <time.h>
5 #include <string.h>
6 #include <stdio.h>
7 #include <pthread.h>
8 #include <sys/select.h>
9 #define BUFFLEN 1024
10 #define SERVER_PORT 8888
11 #define BACKLOG 5
12 #define CLIENTNUM 1024/*最大支持客户端数量*/
13
14 /*可连接客户端的文件描述符数组*/
15 int connect_host[CLIENTNUM];
16 int connect_number = 0;
17
18 //处理客户端请求函数
19 static void *handle_request(void *argv)
20 {
21 time_t now; /*时间*/
22 char buff[BUFFLEN];/*收发数据缓冲区*/
23 int n = 0;
24
25 int maxfd = -1;/*最大侦听文件描述符*/
26 fd_set scanfd; /*侦听描述符集合*/
27 struct timeval timeout; /*超时*/
28 #_sec = 1; /* 阻塞1秒后超时返回 */
29 #_usec = 0;
30
31 int i = 0;
32 int err = -1;
33 for(;;)
34 {
35 /*最大文件描述符值初始化为-1*/
36 maxfd = -1;
37 FD_ZERO(&scanfd);/*清零文件描述符集合*/
38 for(i=0;i<CLIENTNUM;i++)/*将文件描述符放入集合*/
39 {
40 if(connect_host[i] != -1)/*合法的文件描述符*/
41 {
42 FD_SET(connect_host[i], &scanfd);/*放入集合*/
43 if(maxfd < connect_host[i])/*更新最大文件描述符值*/
44 {
45 maxfd = connect_host[i];
46 }
47 }
48 }
49 /*select等待*/
50 err = select(maxfd + 1, &scanfd, NULL, NULL, &timeout) ;
51 switch(err)
52 {
53 case 0:/*超时*/
54 break;
55 case -1:/*错误发生*/
56 break;
57 default:/*有可读套接字文件描述符*/
58 if(connect_number<=0)
59 break;
60 for(i = 0;i<CLIENTNUM;i++)
61 {
62 /*查找激活的文件描述符*/
63 if(connect_host[i] != -1)
64 if(FD_ISSET(connect_host[i],&scanfd))
65 {
66 memset(buff, 0, BUFFLEN);/*清零*/
67 n = recv(connect_host[i], buff, BUFFLEN,0);/*接收发送方数据*/
68 if(n > 0 && !strncmp(buff, "TIME", 4))/*判断是否合法接收数据*/
69 {
70 memset(buff, 0, BUFFLEN);/*清零*/
71 now = time(NULL);/*当前时间*/
72 sprintf(buff, "%24s\r\n",ctime(&now));/*将时间拷贝入缓冲区*/
73 send(connect_host[i], buff, strlen(buff),0);/*发送数据*/
74 }
75 /*更新文件描述符在数组中的值*/
76 connect_host[i] = -1;
77 connect_number --; /*客户端计数器减1*/
78 /*关闭客户端*/
79 close(connect_host[i]);
80 }
81 }
82 break;
83 }
84 }
85
86 return NULL;
87 }
88
89 //处理客户端连接函数
90 static void *handle_connect(void *argv)
91 {
92 int s_s = *((int*)argv) ;/*获得服务器侦听套接字文件描述符*/
93 int s_c = -1;/*连接客户端文件描述符*/
94 struct sockaddr_in from;
95 int len = sizeof(from);
96 /*接收客户端连接*/
97 for(;;)
98 {
99 int i = 0;
100 int s_c = accept(s_s, (struct sockaddr*)&from, &len);/*接收客户端的请求*/
101 printf("a client connect, from:%s\n",inet_ntoa(from.sin_addr));
102 /*查找合适位置,将客户端的文件描述符放入*/
103 for(i=0;i<CLIENTNUM;i++)
104 {
105 if(connect_host[i] == -1)/*找到*/
106 {
107 /*放入*/
108 connect_host[i]= s_c;
109
110 /*客户端计数器加1*/
111 connect_number ++;
112 /*继续轮询等待客户端连接*/
113 break;
114 }
115 }
116 }
117 return NULL;
118 }
119
120 int main(int argc, char *argv[])
121 {
122 int s_s; /*服务器套接字文件描述符*/
123 struct sockaddr_in local; /*本地地址*/
124 int i = 0;
125 memset(connect_host, -1, CLIENTNUM);
126
127 /*建立TCP套接字*/
128 s_s = socket(AF_INET, SOCK_STREAM, 0);
129
130 /*初始化地址接哦股*/
131 memset(&local, 0, sizeof(local));/*清零*/
132 local.sin_family = AF_INET;/*AF_INET协议族*/
133 local.sin_addr.s_addr = htonl(INADDR_ANY);/*任意本地地址*/
134 local.sin_port = htons(SERVER_PORT);/*服务器端口*/
135
136 /*将套接字文件描述符绑定到本地地址和端口*/
137 int err = bind(s_s, (struct sockaddr*)&local, sizeof(local));
138 err = listen(s_s, BACKLOG);/*侦听*/
139
140 pthread_t thread_do[2];/*线程ID*/
141 /*创建线程处理客户端连接*/
142 pthread_create(&thread_do[0],/*线程ID*/
143 NULL,/*属性*/
144 handle_connect,/*线程回调函数*/
145 (void*)&s_s); /*线程参数*/
146 /*创建线程处理客户端请求*/
147 pthread_create(&thread_do[1],/*线程ID*/
148 NULL,/*属性*/
149 handle_request,/*线程回调函数*/
150 NULL); /*线程参数*/
151 /*等待线程结束*/
152 for(i=0;i<2;i++)
153 pthread_join(thread_do[i], NULL);
154
155 close(s_s);
156
157 return 0;
158 }
填写下面表单即可预约申请免费试听! 怕学不会?助教全程陪读,随时解惑!担心就业?一地学习,可全国推荐就业!
Copyright © Tedu.cn All Rights Reserved 京ICP备08000853号-56
京公网安备 11010802029508号 达内时代科技集团有限公司 版权所有