一、服务器
1、单循环服务器
服务器在同一时刻只能响应一个客户端的请求
2、并发服务器模型
服务器在同一时刻可以响应多个客户端的请求
3、TCP和UDP
UDP: 无连接
TCP: 有连接
1).多进程
2).多线程
3).IO多路复用:
为了解决进程或线程阻塞到某个 I/O 系统调用而出现的技术,
使进程不阻塞于某个特定的 I/O 系统调用。
优势:
系统开销小,系统不需要建立新的进程或者线程,也不必维护这些线程和进程。
二、Linux系统IO模型
1.阻塞IO
- scnaf
- getchar
- fgets
- gets
- read
- recv
- recvfrom
1).可以实现多任务同步(多个事件相互影响)
2).可以节省CPU资源开销,提高执行效率
2.非阻塞IO
- 获取文件描述符属性(fcntl---------flag)
- 为文件描述符添加非阻塞属性
- 设置文件描述符属性(fcntl)
1).可以访问多个IO事件
2).配合轮询操作,浪费CPU资源
3.信号驱动IO
1).实现异步IO操作,节省CPU开销
2).只能针对比较少的IO事件
为IO设备增加信号驱动属性(O_ASYNC)
关联SIGIO信号到对应进程 (fcntl(fd, F_SETOWN, getpid());)
注册SIGIO处理函数(signal)
4.多路复用IO
1).select
缺点:
1.select监听文件描述符最大个数为1024 (数组) O(n)
2.select监听的文件描述符集合在用户层,需要应用层和内核层互相传递数据
3.select需要循环遍历一次才能找到产生的事件
4.select只能工作在水平触发模式(低速模式)无法工作在边沿触发模式(高速模式)
2).poll
缺点:
1.poll监测文件描述符不受上限限制 (链表) O(n)
2.poll监听的文件描述符集合在用户层,需要内核层向用户层传递数据
3.poll需要循环遍历一次才能找到产生的事件
4.poll只能工作在水平触发模式(低速模式)无法工作在边沿触发模式(高速模式)
3).epoll
优点:
1.epoll创建内核事件表,不受到文件描述符上限限制 (红黑树) O(logn)
2.epoll监听的事件表在内核中,直接在内核中监测事件效率高
3.epoll会直接获得产生事件的文件描述符的信息,而不需要遍历检测
4.epoll既能工作在水平触发模式,也能工作在边沿触发模式
4).操作方法
1)创建文件描述符集合
2)添加关注的文件描述符到集合中
3)监测IO事件
5).函数接口
1.fcntl
int fcntl(int fd, int cmd, ... /* arg */ );
功能:
设置文件描述符属性
参数:
fd:文件描述符
cmd:F_GETFL 获得文件描述符属性
F_SETFL 设置文件描述符属性
返回值:
F_GETFL:
成功返回获得的属性
失败返回-1
F_SETFL:
成功返回0
失败返回-1
(O_NONBLOCK 非阻塞 O_ASYNC 异步方式)
修改IO属性:
1)获取原有属性
2)增加新的属性
3)设置新的属性
int flag = fcntl(fd, F_GETFL);
flag = flag | O_NONBLOCK; //增加非阻塞属性 flag = flag & ~O_NONBLOCK; //减去非阻塞属性
flag = flag | O_ASYNC; //增加异步属性
fcntl(fd, F_SETFL, flag);
2.select
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
功能:
监听文件描述符集合
参数:
nfds:监测的文件描述符上限值(最大文件描述符的值+1)
readfds:读文件描述符集合
writefds:写文件描述符集合
exceptfds:异常条件的描述符集合
timeout:设置超时时间
NULL:一直等待
返回值:
成功返回产生事件文件描述符个数
失败返回-1
定时时间到达仍没有事件产生返回0
- 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); //文件描述符集合清0
3.poll
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
功能:
监听文件描述符集合中的事件
参数:
fds:文件描述符集合事件数组首地址
nfds:事件个数
timeout:超时时间
返回值:
成功返回产生事件的文件描述符个数
失败返回-1
超时时间到达仍没有产生事件返回0
epoll模型:
1)epoll_create 创建epoll文件描述符集合
2)epoll_ctl 添加关注的文件描述符
3)epoll_wait 监控io事件
4)epoll_ctl 从事件集合中删除完成的文件描述符
4.epoll_create
int epoll_create(int size);
功能:
创建一个监听事件表(内核中)
参数:
size:监听事件最大个数
返回值:
成功返回非负值:表示epoll事件表对象(句柄)
失败返回-1
5.epoll_ctl
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:
在监听事件表中新增一个事件
参数:
epfd:事件表文件描述符
op:EPOLL_CTL_ADD 新增事件
EPOLL_CTL_MOD 修改事件
EPOLL_CTL_DEL 删除事件
fd:文件描述符
events:事件相关结构体
返回值:
成功返回0
失败返回-1
events:
EPOLLIN 读事件
EPOLLOUT 写事件
EPOLLET 边沿触发
LT 水平触发
6.epoll_wait
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
功能:
监听事件表中的事件,并将产生的事件存放到结构体数组中
参数:
epfd: 事件表文件描述符
events: 存放结果事件结构体数组空间首地址
maxevents:最多存放事件个数
timeout: 超时时间
-1: 阻塞等待直到有事件发生
返回值:
成功返回产生事件个数
失败返回-1
超时时间到达没有事件发生返回0