一,select多路复用
1,select(5)函数原型
用来进行select多路复用。效率较低。返回值为正数,就是已经就绪的文件描述符的个数,出错返回负数,超时返回0。在Linux内核有个参数__FD_SETSIZE定义了每个FD_SET的句柄个数,这也意味着select所用到的FD_SET是有限的,也正是这个原因select()默认只能同时处理1024个客户端的连接请求:/linux/posix_types.h: #define __FD_SETSIZE 1024
返回值:
>0
该函数的返回值表示跨所有描述符集的已就绪的总位数。
=0
超时
<0
select出错
#include <sys/select.h>
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout);
int nfds//总共需要从零开始监听的文件描述符的数量,即你需要监听的最大的文件描述符+1,因为他是从零开始数的,这个值指的是数量而不是对应的文件描述符。
fd_set *readfds//有数据到来可读的文件描述符的集合。fd_set 是一个数据类型,他就是一个文件描述符的集合。
fd_set *writefds//文件描述符可写的集合。
fd_set *exceptfds//文件描述符出错,异常的集合
struct timeval *timeout//超时设置。设置为NULL为永不超时。设置为0那么就是非阻塞模式。
//结构体构成,该结构体一般用time
struct timeval
{
long tv_sec; //seconds 秒
long tv_usec; //microseconds 微秒
};
2,FD_ZERO(1)函数原型
用来清空文件描述符集合。
返回值:无。
#include <sys/select.h>
void FD_ZERO(fd_set *set);
fd_set *set//要清空的文件描述符集合的地址,同时也可以用来初始化一个fd_set。
3,FD_SET(2)函数原型
将一个文件描述符加入到某一个文件描述符集合里。
返回值:无。
#include <sys/select.h>
void FD_SET(int fd, fd_set *set);
int fd//要加入fd_set的文件描述符
fd_set *set//文件描述符集合的地址。
4,FD_ISSET(2)函数原型
用来判断指定的文件描述符是否在文件描述符集合中。
返回值:
非零值
该fd在fdset中。
0
该fd不在fdset中。
#include <sys/select.h>
int FD_ISSET(int fd, fd_set *set);
int fd//要判断的文件描述符
fd_set *set//文件描述符集合的地址。
5,FD_CLR(2)函数原型
将给定的文件描述符从集合中删除。
返回值:无
#include <sys/select.h>
void FD_CLR(int fd, fd_set *set);
int fd//要删除的文件描述符
fd_set *set//文件描述符集合的地址。
二,poll多路复用
1,poll(3)函数原型
和select()一样,poll用于多路复用,原理上差不多,但是没有最多同时监听1024个文件描述符的限制。
返回值:
>=0
成功,返回响应的文件描述符的数量。poll()返回结构体中revents域不为0的文件描述符个数。
0
超时。
-1
出错。并设置errno为下列值之一:
EBADF 一个或多个结构体中指定的文件描述符无效。
EFAULTfds 指针指向的地址超出进程的地址空间。
EINTR 请求的事件之前产生一个信号,调用可以重新发起。
EINVALnfds 参数超出PLIMIT_NOFILE值。
ENOMEM 可用内存不足,无法完成请求。
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
struct pollfd *fds//一个结构体,里面包含着我们需要监听的文件描述符。
POLLIN | POLLPRI 等价于 select()的读事件 POLLOUT |POLLWRBAND 等价于 select()的写事件 POLLIN 等价于 POLLRDNORM |POLLRDBAND POLLOUT 等价于 POLLWRNORM
nfds_t nfds//指定数组中监听元素的个数。
int timeout//超时时间,单位是ms毫秒。设置为负数时永不超时,而设置为0时,表示函数不阻塞,立即返回。
struct pollfd
{
int fd; //要监听的文件描述符
short events; // requested events 应用传给内核的事件,即让内核监听什么事件
short revents; // returned events */内核传给我们的应用的事件,即内核发生了什么
};
struct pollfd *fds结构体中事件的可取值
三,epoll多路复用
1,epoll_create(1)函数原型
创建一个额外的文件描述符epfd,同时他也是一个兴趣列表,在epoll文件系统中为这个句柄分配资源。对应的兴趣列表初始化为空。出错返回-1,成功返回epfd的文件描述符。
返回值:
>=0
成功,epoll_fd兴趣列表的文件描述符。
0
超时。
-1
出错。
#include <sys/epoll.h>
int epoll_create(int size);
int size//指定我们通过epoll实例来检查的文件描述符的个数,但是并不是上限,Linux2.6.8后,他只是初始化时候内核分配的初始大小。
2,epoll_ctl(4)函数原型
用来修改epfd中的兴趣列表。
返回值:
0
成功。
-1
失败。
#include <sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epfd//是epoll_create()的返回值,即创建的epoll实例的文件描述符。
int op//想要执行的操作。
int fd//要操作兴趣列表里面的哪一个文件描述符。
struct epoll_event *event//指向epoll_event的一个结构体
struct epoll_event
{
uint32_t events; /* Epoll events :关心的事件*/
epoll_data_t data; /* User data variable */
};
typedef union epoll_data
{
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;//一个联合体,当描述符fd为就绪态的时候,可用来指定传回给调用进程相应的信息
3,epoll_wait(4)函数原型
返回epfd实例中已经处于就绪态的文件描述符信息。
返回值:
0
成功。
-1
失败。
#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
int epfd//是epoll_create()的返回值,即epoll_fd兴趣列表的文件描述符
struct epoll_event *events//接口的返回参数,epoll把发生的事件的集合从内核复制到 events数组中。events数组是一个用户分配好大小的数组,数组长度大于等于maxevents。(events不可以是空指针,内核只负责把数据复制到这个 events数组中,不会去帮助我们在用户态中分配内存)
int maxevents//表示本次可以返回的最大事件数目,通常maxevents参数与预分配的events数组的大小是相等的。
int timeout//超时,单位ms,-1永不超时,0为非阻塞模式。
*struct epoll_event evlist: