关于网络模型的一些概念

五中IO模型:

1)阻塞IO,比如socket,一直阻塞到对方数据填充recv缓冲区,一直等到IO操作彻底返回才回到用户空间,

         最简单的改进是使用多进程或者多线程,让一个连接的阻塞不影响其他

        int accept(int fd,struct sockaddr *addr,socklen_t *addrlen); //accept接口原型


2)非阻塞IO:但是这种是一直轮询内核数据,并不阻塞,会造成CPU资源的浪费,一般不使用,被调用后立即

            返回给用户一个状态值不必等到IO操作彻底完成

        fcntl(fd,F_SETFL,O_NONBLOCK);    //将句柄设置为非阻塞状态


连接池和线程池的概念:就是维持一定的连接数,意在降低创建和销毁进程的频率,让空闲的进程或线程

    重新承担新的执行任务,但也只是在一定程度上缓解了频繁调用io接口带来的资源占用


3)IO复用:用select来管理多个文件描述符,一旦有一个有数据写入,select就返回,也就是阻塞在select,

不阻塞在recv,select可以看成管理者,用它来管理多个IO,一旦其中的一个或多个IO检测到我们感兴趣的事件,select就返回,返回值为检测到的事件的个数以及是哪些IO发生的事件,这样我们就可以遍历这些事件,进而

去处理它,若直到超时都未检测到事件,则返回0,它的优势不在于能够处理的更快,而在于能够处理更多的连接


在IO复用模型中,对于每一个socket,其实是非阻塞的,但是整个用户进程是阻塞的,只是它被阻塞在select,

而不是socket IO

select(int nfds, fd_set *restrict readfds, fd_set *restrict writefds,

         fd_set *restrict errorfds, struct timeval *restrict timeout);

参数说明:1 读写异常集合中的文件描述符的最大值+1

         2 读集合

         3 写集合

         4 异常集合

         5 超时描述的结构体


select在检测到可读事件之后,即时响应recv()操作,并根据接收到的数据准备好待发送数据,并将

对应的句柄值假如到writefds,准备下次的可写事件的select检测,同样,如果select发现某个句柄

发现可写事件,会立即做send操作,并准备好下一次的可读事件操作


事件驱动模型:每一个执行周期都会检测或者探测一次或者一组事件,一个特定的事件会触发某个特定

的响应


但是,注意select模型接口并不是实现事件驱动的最好的选择,因为当需要探测的句柄值较大的时候,

select接口本身需要消耗大量的实际去轮询各个句柄,很多操作系统提供了更为高效的接口,

比如Linux提供了epoll,而BSD提供了kqueue,Solaris提供了/dev/poll等但由于各系统的epoll

接口实现差异较大,所以用epool实现的服务器实现跨平台比较难,libevent和libev库是属于事件

驱动库 ,实际上Linux2.6之后也引入了支持异步的io操作如aio_read , aio_write


4)信号驱动IO:安装一个信号处理程序sigaction,有数据写入信号到来,再用信号通知应用进程有数

据到来,执行recv接收,把数据从内核拉取到用户空间,也不常用


5)异步IO:效率最高,用aio_read来实现的,没有数据时阻塞,有数据到来,直接copy到用户空间buf,

应用进程直接处理数据即可,不用再调用recv函数拉取,是一种主动推送的机制



poll函数的返回值errno:

1)EBADF:一个或者多个结构体中定义的文件描述符无效

2)EFAULTfds:指针指向的地址超出进程的地址空间

3)EINTR:请求的事件之前产生的一个信号,调用可以重新发起

4)EINVALnfds:参数超出PLIMIT_NOFILE的值

5)ENOMEM:可用内存不足,无法完成请求




epoll是在Linux2.6内核提出的,是select和poll的增强版,更加灵活,没有文件描述符的限制

int epoll_create(int size)  size是要监听的数目

int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event) epoll的事件注册函数

int epoll_wait(int epfd,staruct epoll_event *events,int maxevents,int timeout);

一点解释:

1)size应为最大监听数fd+1,创建好epoll句柄后它就会占用一个fd的值,在Linux下,看

/proc/fd/是可以看到这个fd的值的,所以在使用完epoll后必须close关闭,否则可能造成fd被耗尽

2)ctl的参数说明:

   a)create的返回值  

   b)表示动作,用epoll_ctl_add  epoll_ctl_mod epoll_ctl_del三个宏来描述 

   c)要监听的fd

   d)要监听的事件epollin可读  epollout可写  epollpri有紧急数据可读

epollerr 对应fd发生错误

   e)fd被挂断

   f)将epoll设为边沿处罚

   g)epolloneshot只监听一次事件,若需要再次监听,需重新加入到epoll队列 


select  poll和epoll的区别:

三者都是多路IO复用机制,可以监视多个描述符,一旦某个描述符九尾,可以通知程序进行相应的读写操作,但本质上都是同步IO,他们都需要在读写事件就绪后自己负责读写,而异步IO会把主动数据copy到用户空间

1)一般认为poll比select高效的原因:

   a.poll不要求开发组在计算最大文件描述符(fd)时进行+1的操作

   b.在应付大数目的fd时速度更快,因为select内核需要大量检测fd对应的fd_set中每一个bit位,会比较耗时

   c.select可监控的fd是固定的,也相对较少。poll可创建特定大小的数组来保存fd,不受fd大小的影响,而且可以监控的fd的数目远大于select

   d.对select来说,所监控的fd_set在select返回之后会发生变化,在下次进入select之前需要重新初始化需要监控的fd_set,poll将输入和输出分块,允许备件款的文件数组被复用而无需重新初始化

   f.select的超时参数在返回时也是未定义的,为考虑移植性,每次超时在下次进入select之前需重新设置超时参数


2)select的优点:

   a.可移植性更好,在某些unix系统不支持poll

   b.对超时提供了更好的精度,而poll精度较差


3)epoll的优点:

   a.支持一个进程打开最大数目的socket描述符FD,可以使用cat /proc/sys/fd/file-max查看

   b. IO效率不随FD数目的增加线性下降

   c.使用mmap家属内核与用户控件的消息传递





相关内容推荐