因为对于任何句柄 ( file descriptor ) select 函数都能检测出其状态变化,对于用于 listen 的 socket 也是一样。
只要把用于 listen 的 socket 加入 ( FD_SET ) 到 select 检测的集合里,当有连接到来时 select 就能判断到。因为 select 函数能处理的是句柄集合,所以加入这样一个 socket 并不与 select 判断其它 socket 的状态有任何冲突。
- 实现片段代码:
#define MAX_NUM_ONLINE_SOCKET 100
int lsn_sock_fd;
int client_sock_fd[MAX_NUM_ONLINE_SOCKET];
fd_set rdfds;
int maxfds;
int tmp_fd;
struct time tv;
int retval;
int i;
maxfds = -1;
for(i = 0; i < MAX_NUM_ONLINE_SOCKET; i++) client_sock_fd[i] = -1;
lsn_sock_fd = socket(AF_INET, SOCK_STREAM, 0);
/* 设置监听的地址和端口 */
/* 调用 bind 把地址信息与 socket 绑定到一起 */
listen(lsn_sock_fd, 2);
while(1) {
maxfds = 0;
FD_ZERO(&rdfds);
if(lsn_sock_fd > 0) {
FD_SET(lsn_sock_fd, &rdfds); /* 在这里把用于 listen 的 socket 加入到 select 判断的句柄集合里来 */
if( lsn_sock_fd > maxfds) maxfds = lsn_sock_fd;
}
for(i = 0; i < MAX_NUM_ONLINE_SOCKET; i++) {
if(client_sock_fd[i] > 0) {
FD_SET(client_sock_fd[i], &rdfds); /* 把所有在线客户端连接加入到 select 检测的集合中来 */
if( client_sock_fd[i] > maxfds) maxfds = client_sock_fd[i];
}
}
tv.tv_sec = 1;
tv.tv_usec = 0;
if(maxfds < 1) continue;
retval = select(maxfds + 1, &rfds, NULL, NULL, &tv);
if(retval < 0) {
printf("select 出错,错误编号:%d,错误信息:%s ", errno, strerror(errno));
break;
}
else if(!retval) continue; /* listen 的 socket 上没有任何连接到来,在线的所有连接上也没有任何一个上有数据到来 */
if(FD_ISSET(lsn_sock_fd, &rdfds)) { /* 说明 listen 的 socket 上有新的连接到来了 */
tmp_fd = accept(lsn_sock_fd, ......);
for(i = 0; i < MAX_NUM_ONLINE_SOCKET; i++) {
if(client_sock_fd[i] < 0) {
client_sock_fd[i] = tmp_fd;
break;
}
}
if(i == MAX_NUM_ONLINE_SOCKET) {
printf("连接太多了,我最多只能接受%d个连接同时在线 ", MAX_NUM_ONLINE_SOCKET);
close(tmp_fd);
}
}
for(i = 0; i < MAX_NUM_ONLINE_SOCKET; i++) {
if(FD_ISSET(client_sock_fd[i], &rdfds)) { /* 说明第 i 个客户端连接上有数据到来了 */
recv(client_sock_fd[i], ......);
/* 对这个连接进行其它操作 */
send(client_sock_fd[i], ......);
/* 如果这个连接处理完毕了就要 close 它,并执行 client_sock_fd[i] = -1 ; */
}
}
}
From:http://hi.baidu.com/beibeiboo/item/3b6e0ecb7e6d0f50ac00ef7a