Linux--select
select函数概述
select允许程序可以监视多个文件描述符(套接字)的(可读,可写,异常),直到一个或多个文件描述符(套接字)准备就绪(超时),select解阻塞继续执行。
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
select参数介绍
nfds: 是这三个集合中编号最高的文件描述符是加1。
readfds:监视readfds集合中的描述符是否读操作准备就绪。
writefds:监视writefds集合中的描述符是否写操作准备就绪
exceptfds:监视exceptfds集合中的描述符是否发生了异常。
timeout:超时时间,如果在超时时间内没有任意描述符准备好或异常,那么select超时时间一到也会解阻塞struct timeval
{
long tv_ sec; /* seconds */
long tv_ usec; /* microseconds */
};timeout有三种情况:
timeout为NULL 表示永远等待下去
timeout中所有成员问0, 不等待立即解阻塞
timeout中成员有固定的时间 表示等待该时间返回值:
> 0:表示就绪的文件描述符数量。
=0:表示超时。
-1:表示select出错。
描述符集合操作API
集合类型
fd_set
清空集合
void FD_ ZERO( fd_ set *fdset);
将fd描述符 添加到集合中
void FD_ SET( int fd, fd_ set *fdset);
将fd描述符 从集合中删除
void FD_CLR( int fd, fd_ set *fdset);
判断fd描述符 是否在集合中
int FD_ ISSET( int fd, fd_ set *fdset);
示例代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>//socket
#include <netinet/in.h> //struct sockaddr_in
#include <strings.h>
#include <sys/select.h>
#include <arpa/inet.h>int create_tcp_socket(unsigned short port);
void sys_err(const char *err);int main(int argc,char *argv[]) {
int lfd = create_tcp_socket(9999);
fd_set old_set,r_set;
FD_ZERO(&old_set);
FD_SET(lfd,&old_set);//将lfd添加到old_set中
int maxfd = lfd;
while (1)//select 需要循环监听文件描述符的状态
{
fd_set r_set = old_set;
int nready = select(maxfd+1,&r_set,NULL,NULL,NULL);
if(nready < 0){
sys_err("select");
}else if(nready > 0){
if(FD_ISSET(lfd,&r_set)){
//printf("connect\n");
struct sockaddr_in cil_addr;
socklen_t cli_len = sizeof(cil_addr);
int cfd = accept(lfd,(struct sockaddr *)&cil_addr,&cli_len);
printf("connect %s : %hu\n", inet_ntoa(cil_addr.sin_addr),ntohs(cil_addr.sin_port));
if(cfd > maxfd)
maxfd = cfd;
FD_SET(cfd,&old_set);
if(--nready == 0)
continue;
}
int i = 0;
for (i = lfd+1; i <= maxfd; i++)
{
if(FD_ISSET(i,&r_set)){
unsigned char buf[1500] = "";
int n = recv(i,buf,sizeof(buf),0);
if(n < 0){
perror("recv");
}else if (n == 0)
{
FD_CLR(i,&old_set);
close(i);
printf("退出了\n");
}else if (n > 0)
{
send(i,buf,n,0);
}
}
}
}
}
close(lfd);
return 0;
}int create_tcp_socket(unsigned short port){
int lfd = socket(AF_INET,SOCK_STREAM,0);
if(lfd < 0)
sys_err("socket error");
int opt = 1;
setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
struct sockaddr_in my_addr;
bzero(&my_addr,sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(port);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(lfd,(struct sockaddr *)&my_addr,sizeof(my_addr));
if(ret < 0)
sys_err("bind error");
listen(lfd,128);
return lfd;
}void sys_err(const char *err){
perror(err);
_exit(-1);
}