Linux--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);
//参数一:想要监控的套接字(文件描述符)的最大值加一
//参数二:监控读事件
//参数三:监控写事件
//参数四:监控异常,不用就写NULL
//参数五:超时时间
//参数五 1.NULL永久等待。2.用struct timeval结构体,固定时间。3.struct timeval结构体写0,不等。
struct timeval {
           long    tv_sec;         /* seconds */
           long    tv_usec;        /* microseconds */
       };
       
struct timespec {
       	   long    tv_sec;         /* seconds */
           long    tv_nsec;        /* nanoseconds */
       };

使用参数二监控读事件时,提供四个函数

void FD_CLR(int fd, fd_set *set);   //清除指定fd
int  FD_ISSET(int fd, fd_set *set);  //查看fd是否存在
void FD_SET(int fd, fd_set *set);  //添加fd
void FD_ZERO(fd_set *set);  //全部清空

当有一个或者多个读事件就绪,就是读到了数据,就把该程序(进程)从所有连接的等待队列删除,添加到就绪队列。并且循环把没有读就绪的fd套接字从参数二中结构体中删除。

select的返回值:就绪的套接字(文件描述符)的个数。也就是参数二里面还有几个文件描述符。

示例程序:

一个服务器程序,一个客户端程序
客户端可以启动多个。通过select跟服务器程序连接,并完成写操作,然后服务器把刚刚写的内容给发回来。

服务器程序:

#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>

int tcp_init() {
int lfd = socket(AF_INET, SOCK_STREAM, 0); 
int op = 1;

setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &op, sizeof(op));
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(9898);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
int r = bind(lfd, (struct sockaddr*)&addr, sizeof(addr));
if ( r == -1 ) perror("bind"),exit(1);

listen(lfd, 10);
return lfd;
}

int main( void ) { 
int lfd = tcp_init();
int clients[FD_SETSIZE];
fd_set rset, allset;
int maxfd, i;
for (i=0; i<FD_SETSIZE; i++)
clients[i] = -1; 
FD_ZERO(&rset);
FD_ZERO(&allset);
FD_SET(lfd, &allset);
maxfd = lfd;
int maxi = -1;

for ( ; ; ) {
rset = allset;
int nready = select(maxfd+1, &rset, NULL, NULL, NULL);
if ( nready <= 0 ) continue;
if ( FD_ISSET(lfd, &rset) ) {
int cfd = accept(lfd, NULL, NULL);
for (i=0; i<FD_SETSIZE; i++) {
if ( clients[i] == -1 ) {
clients[i] = cfd;
maxfd = maxfd > cfd ? maxfd : cfd;
if ( i > maxi )
maxi = i;
}

printf("i=%d, cfd=%d, maxfd=%d\n", i, cfd, maxfd);
break;
}
if ( i == FD_SETSIZE ) {
printf("too many client\n");
exit(0);
}
FD_SET(cfd, &allset);
if ( --nready <= 0 )
continue;
}

for ( i=0; i<=maxi; i++) {
int fd = clients[i];
if ( fd == -1 ) continue;
if ( FD_ISSET(fd, &rset) ) {
char buf[1024] = {};
int r = read(fd, buf, 1024);
if ( r <= 0 ) {
close(fd);
clients[i] = -1;
FD_CLR(fd, &allset);
} else {
write(fd, buf, r);
}
if ( --nready <= 0 )
break;
}
}
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值