作用:(在一段时间内)检测一个描述符集合的状态。
int select(int nfds,fd_set *readfds,
fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);
nfds 目标描述符集合中描述符的数量
readfds 可读性
writefds 可写性
exceptfds 异常情况
timeout 时长
select动作仅检查一个描述符集合的状态,执行完毕后会清空整个描述符集合
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); 清空一个集合
在linux中所在位置:x86_64-linux-gnu/sys/select.h
示例:
typedef struct{
#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
} fd_set;
typedef long int __fd_mask; 长整型
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
/*全局变量*/
fd_set fds;/*描述符集合*/
/*获取描述符集合的最大值*/
static int getNumofFds(fd_set *p_fds){
int max;
int i;
for(i = 0;i < FD_SETSIZE;i++){/*FD_SETSIZE 象征集合能够存放最大的描述符数量0 - 1023*/
if(FD_ISSET(i,p_fds)){ /*如果检查到该描述符存在于集合中*/
max = i;
}
}
return max;
}
/*主函数*/
int main(){
int optval = 1;
int num_of_fds;
struct timeval time_value;
int i;
fd_set tmp_fds;
int select_retval;
char buffer[512] = {0};
ssize_t recv_ret;
int listen_skt = socket(PF_INET,SOCK_STREAM,0);/*监听套节字*/
if(listen_skt < 0){
perror("socket");
return -1;
}
/*服务端监听套接字*/
if(setsockopt(listen_skt,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval))){
perror("setsockopt");
return -1;
}
struct sockaddr_in server_addr;
server_addr.sin_family = PF_INET;
server_addr.sin_port = htons(60000);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
/*绑定本机地址和端口*/
if(bind(listen_skt,(const struct sockaddr *)&server_addr,sizeof(server_addr))){
perror("bind");
return -1;
}
/*设置监听端口*/
if(listen(listen_skt,10)){
perror("listen");
return -1;
}
system("clear");
printf("waiting client connect...\n");
FD_ZERO(&fds); /*清空集合(初始化)*/
FD_SET(listen_skt,&fds); /*将监听套接字放入集合中*/
while(1){
time_value.tv_sec = 3;
tmp_fds = fds; /*拷贝一个集合*/
num_of_fds = getNumofFds(&tmp_fds) + 1;
select_retval = select(num_of_fds,&tmp_fds,NULL,NULL,&time_value);
printf("%d fd in fds.\n",num_of_fds);
if(select_retval == 0){
printf("timeout\n");
perror("select");
}else if(select_retval > 0){ /*有返回值*/
if(FD_ISSET(listen_skt,&tmp_fds)){
int server_skt = accept(listen_skt,NULL,0); /*接收连接*/
if(server_skt < 0){
perror("accept");
return -1;
}
FD_SET(server_skt,&fds);
printf("client %d connected.\n",server_skt);
usleep(1);
}else{
for(i = 0;i < num_of_fds;i++){
if(FD_ISSET(i,&tmp_fds)){
recv_ret = recv(i,buffer,sizeof(buffer),0);
if(recv_ret == 0){
break;
}
if(recv_ret < 0){
perror("recv");
break;
}
printf("[recv]:%s\n",buffer);
}
}
}
}
}
return 0;
}