Linux网络编程模型

网络IO模型一共有四种:

  1. 阻塞IO模型
  2. 非阻塞IO模型
  3. 多路IO复用模型
  4. 异步IO模型

1:阻塞IO模型

在这里插入图片描述
IO执行分为两个阶段:
等待数据:比如还没有收到一个完整的TCP包,系统内核就要等待足够的数据到来。
拷贝数据:数据准备好了,系统将数据从内核拷贝到用户内存中,然后系统内核返回结果。
阻塞式IO要等拷贝数据完成后,进程才接触阻塞状态。
大部分的socket接口都是阻塞型的,阻塞状态下,进程无法做任何事情,因此一种简单的解决方案就是为每个请求分配一个线程。
下面看下accept接口原型

//第一个参数是 listen 和 bind 中沿用下来的socket句柄
//返回值是新的和fd同类的socket句柄,这个句柄就是后续 read() 和 recv()的输入参数。
int accept(int fd, struct sockaddr *addr, socklen_t *addrlen);

但是这种解决方案的缺陷在于,无论进程还是线程,都会大量占用系统资源,因此一种解决方案就是使用线程池和连接池,复用已有的线程和连接。
但是池总是有上限的,因此多线程模型的瓶颈可以用 非阻塞模型 来尝试解决。

2:非阻塞IO模型

在这里插入图片描述
使用下面函数,可以将句柄设置为非阻塞状态:

fcntl(fd, F_SETFL, O_NONBLOCK);

这个模型中会使用recv来检查操作是否完成,会占用大量cpu资源,因此是不被推荐的。select()多路复用模式,可以一次检测多个连接是否活跃。

三:多路IO复用模型

在这里插入图片描述
也称为事件驱动IO。基本原理是有个函数,比如select,会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程,如果没有就阻塞在select那。

select()的事件驱动模型只用单线程执行,占用资源极少,不消耗太多的cpu资源,也能够为多客户端提供服务,但如果要探测的句柄值较大时,select()接口本身需要消耗大量时间去轮询各个句柄,Linux中的epoll效率更高。

由于只有单线程,一旦事件响应执行体过于庞大,对于整个系统来说,也是灾难性的。常见的事件驱动库 libevent、libev等可以屏蔽上述问题。

四:异步IO模型

在这里插入图片描述
内核不需要检查IO的操作状态,也不需要主动的拷贝数据,内核完成后会给进程发信号。

几种IO模型的比较:
在这里插入图片描述

下面就到API部分了:
select 函数原型

//maxfdp
//fd_set 一个结构体,可以理解为一个集合,这个集合中存放的是文件描述符
//maxfdp 文件描述符的范围
// readfds、writefds、errorfds 分别用于监视各种文件
// timeout 超时时间
int select(int maxfdp, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);

//fd_set 可以通过一些宏由人为来操作。
fd_set set;
FD_ZERO(&set);	//将set清0
FD_SET(fd, &set);	//将fd加入set
FD_CLR(fd, &set);	//将fd从set中清除
FD_ISSET(fd, &set);	//如果fd在set中,则为真

poll 函数原型

//fds pollfd数组,表示监控的文件描述符 
//nfds 
int poll(struct pollfd *fds, unsigned int nfds, int timeout);

//每一个pollfd结构体指定了一个被监视的文件描述符
struct pollfd{
	int fd;	//文件描述符
	short events;	//等待的事件(事件掩码)
	short revents;	//实际发生了的事件(操作结果的掩码)
}

epoll 函数原型
在Linux 2.6内核中提出,是之前select和poll的增强版本,更加灵活。一共有三个接口

//创建一个epoll的句柄,size用来告诉内核要监听的数目,创建epoll句柄后,它会占用一个fd值,因此使用完后必须close
int epoll_create(int size);
//事件注册函数
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
//等待事件的产生
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

select、poll、epoll的区别
select、poll、epoll都是多路IO复用的机制。可以监视多个描述符,一旦某个描述符就绪,就能够通知程序进行读写操作。但其本质都是同步IO,因为它们都需要在读写事件就绪后自己负责读写,即是阻塞的,而异步IO无需自己负责进行读写,会负责把数据从内核拷贝到用户空间。

通常来说,poll比select要好,支持扫描的文件操作符(socket)数量更多,但是select的可移植性要好些。
select、poll每次都要对全部的文件描述符进行扫描,一旦文件描述符过多,效率就会直线下降。但由于网络延迟,任意时刻只有部分的socket是活跃的,使用epoll只会对活跃的进行扫描(由fd上的callback实现),epoll使用mmap避免数据从内核到用户空间的拷贝。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值