专业做刀具网站的公司广州市口碑seo推广
select函数简介:
select是Linux中常用的多路复用IO机制,它允许程序同时监控多个文件描述符(可以是套接字socket,也可以是普通文件)的读、写和异常事件。
#include <sys/select.h>
#include <sys/time.h>
int select(int maxfd, fd_set* readset, fd_set* writeset, fd_set* exceptset,
const struct timeval* timeout);//参数:
//maxfd:监视对象文件描述符数量。
//readset:将所有关注“是否存在待读取数据”的文件描述符注册到fd_set变量,并传递其地址值。
//writeset: 将所有关注“是否可传输无阻塞数据”的文件描述符注册到fd_set变量,并传递其地址值。
//exceptset:将所有关注“是否发生异常”的文件描述符注册到fd_set变量,并传递其地址值。
//timeout:调用select后,为防止陷入无限阻塞状态,传递超时信息。//返回值:错误返回-1,超时返回0。当关注的事件返回时,返回大于0的值,该值是发生事件的文件描述符数。
关于文件描述符的操作,以下四个函数是用于处理fd_set类型数据的:
FD_ZERO(fd_set *set): 这个函数用于清除一个fd_set的所有位,即初始化一个fd_set。
FD_SET(int fd, fd_set *set): 这个函数用于将特定的文件描述符fd加入到fd_set中。
FD_CLR(int fd, fd_set *set): 这个函数用于将特定的文件描述符fd从fd_set中移除。
FD_ISSET(int fd, fd_set *set): 这个函数用于检查特定的文件描述符fd是否在fd_set中,如果在,函数返回非零值,否则返回0。
使用这些函数,我们可以方便地对文件描述符集合进行操作,以便于使用select函数进行IO操作的复用。
select函数优缺点:
优点:在poll和epoll面前主要是缺点,它出现的比较早。
缺点:
-
文件描述符有限:默认为1024(这个值可以修改)。如果需要处理的并发连接数过多,select可能无法满足需求。
-
多次copy:每次select都要把文件描述符拷贝到内核,增加了系统的开销。
-
使用复杂:select在返回时,只会告诉用户哪些描述符集合是就绪的,但并不会直接告诉用户哪一个具体的文件描述符就绪,用户需要自己去遍历这些集合,操作比较复杂。
-
重复操作:每次select返回后,所有未就绪的文件描述符都会被移除,因此每次使用都需要重新向集合中添加描述符。
select可以让一个线程同时处理多个客户端的连接。而避免了太多线程导致占用资源过大多,下边是一个tcp协议的服务器代码示例。客户端可以用网络调试助手进行模拟,服务器功能:客户端发送过来的数据接收后,再转发给客户端。
#include<stdlib.h>
#include<stdio.h>
#include<netinet/in.h>
#include<string.h>
#include<errno.h>
#include<sys/socket.h>
#include<sys/select.h>#define SERV_PORT 8888
#define BUFFER_SIZE 128int main(void)
{int sockfd = socket(AF_INET,SOCK_STREAM,0);struct sockaddr_in servaddr;memset(&servaddr,0,sizeof(struct sockaddr_in));servaddr.sin_port = htons(SERV_PORT);servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);if(-1 ==bind(sockfd,(struct sockaddr*)&servaddr,sizeof(struct sockaddr))){perror("bind");return -1;}listen(sockfd,10);fd_set fds1,fds2;FD_ZERO(&fds1);FD_SET(sockfd,&fds1);int maxfd = sockfd;printf("select test:\n");while(1){fds2 = fds1;int nready = select(maxfd+1,&fds2,NULL,NULL,NULL);if(FD_ISSET(sockfd,&fds2)){struct sockaddr_in clientaddr;socklen_t len = sizeof(clientaddr);int clientfd = accept(sockfd,(struct sockaddr*)&clientaddr,&len);FD_SET(clientfd,&fds1);maxfd = clientfd;printf("clientfd:%d\n",clientfd);}int i = 0;for(i = sockfd + 1;i<=maxfd;i++){if(FD_ISSET(i,&fds2)){char buffer[BUFFER_SIZE] = {0};int count = recv(i,buffer,BUFFER_SIZE,0);if(!count){printf("disconnect\n");FD_CLR(i,&fds1);close(i);break;}send(i,buffer,BUFFER_SIZE,0);printf("clientfd:%d,count:%d,buffer:%s\n",i,count,buffer);}}}
}