服务器和客户端建立连接示意图
利用select()
函数:
Server服务器利用select进行监听需要建立连接的Client,Server事先创建好lfd并交给select()函数进行监听,若有客户端需要建立连接,就反馈给服务器 ,服务器调用accpet()函数返回cfd文件描述符给select()函数。
select多路IO转换,原理:借助内核, select 来监听,客户端连接、数据通信事件。
①fd_set rset:创建一个名为rset的文件描述符集合
②void FD_ZERO(fd_set *set):清空一个文件描述符集合 。FD_ZERO(&rset);
③void FD_SET(int fd, fd_set *set):将待监听的文件描述符,添加到监听集合中。FD_SET(3, &rset);FD_SET(5, &rset);FD_SET(6, &rset); 将3、5、6号文件描述符添加到监听集合中。
④void FD_CLR(int fd, fd_set *set):将一个文件描述符从监听集合中移除。FD_CLR(4, &rest);
⑤int FD_ISSET(int fd, fd_set *set):判断一个文件描述符是否在监听集合中。FD_ISSET(4, &rest);返回值,在返回1,不在返回0
int select
(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
select()参数及返回值
:
nfds
:监听的所有文件描述符中,最大文件描述符+1
readfds
:读 文件描述符监听集合传入传出参数
writefds :写 文件描述符监听集合传入传出参数通常NULL
exceptfds:异常 文件描述符监听集合 传入传出参数 通常NULL
timeout:>0,设置监听超时时长;NULL: 阻塞监听;0: 非阻塞监听,轮询
返回值:>0 所有监听集合中,满足对应事件的总数;0 无满足监听条件的文件描述符;-1 errno
select的优缺点
缺点:
①监听上限受文件描述符限制,最大1024。
②检测满足条件的fd. 自己添加业务逻辑提高小。 提高了编码难度
优点:跨平台
,win、linux、macOS、Unix。
int epoll_create
(int size):创建一个监听红黑树
size:创建的红黑树的监听节点数量。(仅供内核参考)
返回值:指向新创建的红黑树的根节点的fd;失败: -1 errno
int epoll_ctl
(int epfd, int op, int fd, struct epoll_event * event):操作监听红黑树
epoll_ctl()参数及返回值
①epfd : epoll_create 函数的返回值 epfd文件描述符
② op: 对该监听红黑树所做的操作
EPOLL_CTL_ADD添加fd到 监听红黑树上
EPOLL_CTL_MOD修改fd在 监听红黑树上的监听事件
EPOLL_CTL_DEL将一个fd 从监听红黑树上摘下(取消监听)
③fd: 待监听的fd
④ event: 本质是struct epoll_event 结构体地址。
成员
events:EPOLLIN,EPOLLOUT,EPOLLERR
data联合体:int fd(对应监听事件的fd),void *ptr,uint32_t u32,uint64_t u64
⑤ 返回值成功0;失败 -1 errno
int epoll_wait
(int epfd, struct epoll_event * events, int maxevents, int timeout): 阻塞监听
epoll_wait()参数及返回值
①epfd : epoll_create 函数的返回值 epfd文件描述符
②events: 传出参数,看作数组, 满足监听条件的那些 fd结构体
③maxevents:数组 元素的总个数。 直接写1024 struct epoll_event evnets[1024]
④timeout >0: 超时时长。 单位:毫秒
-1: 阻塞等待
0: 不阻塞
⑤返回值 >0: 满足监听的 总个数。 可以用作循环上限
0:没有fd满足监听事件
-1:失败 errno
ET模式(边沿触发)
缓冲区剩余未读尽的数据不会导致epoll_wait 返回,新的事件才会触发。
struct eopll_event event,event.events = EPOLLIN | EPOLLE。
只有数据到来才触发,不管缓存区是否还有数据。
LT模式(水平触发)
默认采用模式,缓冲区剩余未读尽的数据会导致epoll_wait 返回。
水平触发只要有数据都会触发。
结论:
epoll 的 ET模式, 高效模式。但是只支持 非阻塞模式。
struct epoll_event event,event.events = EPOLLIN | EPOLLET。
epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &event)。
int flg = fcntl(cfd, F_GETFL),flg | = O_NONBLOCK,fcntl(cfd, F_SETEL, flg)。