一、常规socket通信
1.socket,创建socket fd
2.bind,将要监听的ip和端口绑定到socket fd中
3.listen,设置等待队列长度,并且开始监听端口
4.accept,阻塞等待,直到有已经连接的socket,获取其fd进行read操作
基于事件的socket通信
1.前三步不变,1,2,3
2.唯一改变的是accept,accept为应用程序不断阻塞轮训操作系统等待已经有连接的socket,但是read操作可能还没有到达,
这时候如果便开启线程或者进程进行业务处理,那么会阻塞
而使用改进的事件机制,其能在有数据到达的时候才进行通信
二、select
1.nfds为当前有效的最大fd+1,以让内核遍历所有可能设置的fd进行查看是否有合适事件到达
2.1024的bit数组,每一个bit代表一个fd(进程fd从0开始增加),通过FD_SET,FD_CLR,FD_ISSET,FD_ZERO工具宏进行处理
3.timeout, struct timeval超时事件
注意点:2.每次select后,传入的fd_set会被重新设置为实际有效的fd,ret为个数,0为超时,3.timeout也会被重新设置为剩余时间,
因此每次调用select均需要重新设置fd_set和timeout的值
注意点:每次的fd_set维护在用户态内存中,那么每次调用函数,均需要从用户态拷贝到内核态,且再不修改源码的情况下,fd数量最大为1024,支持io多路复用
三、poll
1.fd数组交由用户自己创建,即理论上数量不受限制
2.事件的选择同存放在pollfd结构体中,而返回的事件在pollfd的revents
3.nfds代表当前fd数组的数量
4.timeout为毫秒数值型
注意点:
1.每次的fd数据在用户态内存中,那么每次调用函数,均需要从用户态拷贝到内核态
2.fd大小由用户自己定义,理论上无限
3.采用pollin, pollout等作为fd的事件注册,而不需要分割开三个fd_set数组
4.fd设置为-1代表跳过(删除)该fd
5.支持io多路复用
四、epoll
1.fd数组及事件交由内核管理,即不需要再每次调用的时候从用户态拷贝到内核态
2.告知内核需要维护fd数组,通过epoll_create来创建
3.系统调用通过epoll_ctl来告知内核fd数组的添加(EPOLL_CTL_ADD)、删除(EPOLL_CTL_DEL)、更新操作(EPOLL_CTL_MOD),注意添加的时候结构体epoll_event,除了设置events外,还需要设置data.fd(fd文件描述符)好让内核返回时正确赋值
4.epoll_wait,两种模式,默认模式level triggered(水平触发),同select和poll语义,则只要fd还有数据可以读取,或者还是空闲的位置可以写,则epoll_wait会返回对应的fd,而不会一直阻塞,可选模式edge triggered(边缘触发),只有当fd中的数据比上一次epoll_wait的时候有发生变化,才会使epoll_wait返回对应的fd,否则会阻塞,也就是说如果在epoll_wait后的fd进行读取操作没有全部完成,并且客户端已经发送完数据了,那么下次的epoll_wait便会阻塞,而不会返回该fd
5.maxevents表示最大一次处理多少个事件,timeout为毫秒数值型
注意点:
1.epoll相比select、poll,其fd数组由用户态转交由内核态来管理,减少了每次调用的内存拷贝操作
2.io多路复用,增加了edge triggered(边缘触发)语义,只有fd中的数据发送改变才会返回fd