socket IO

一、I/O模型

I/O模型:

一个输入操作通常包括两个阶段:1>等待数据准备好;2>从内核向进程复制数据。对于一个套接字上的输入操作,第一步通常涉及等待数据从网络中到达。当所等待的分组到达时,它被复制到内核中的某个缓冲区。第二步就是把数据从内核缓冲区复制到应用进程缓冲区。

unix下有五种I/O模型:

*阻塞式I/O

*非阻塞I/O

*I/O复用(select/poll/epoll)

*信号驱动式I/O(SIGIO)

*异步IO(AIO)

1.1 阻塞式I/O。

应用进程被阻塞,直到数据复制到应用进程缓冲区才返回。下图中recvfrom用于接收socket传来的数据,并复制到应用进程的buf中。进程在阻塞的过程中,不消耗CPU时间,因此系统执行效率较高。

1.2 非阻塞式I/O

应用进程在执行系统调用之后,如果数据没有准备好,系统会准备一个错误码。应用进程可以继续执行。但是需要不断地执行系统调用获知I/O是否完成,这种方式称为轮询(polling)。由于CPU需要处理更多的系统调用,因此这种模型是比较低效的。

需要注意的是阻塞与非阻塞I/O都是同步IO,也即I/O操作的第二个阶段均是阻塞的。但是阻塞I/O要求I/O的两个阶段均完成了才可以返回;非阻塞I/O在I/O的第一个阶段没数据就可以立即返回。这样系统就可以从内核空间切换到用户空间,这时就系统可以做另外的事情。所说的非阻塞实际上是第一阶段的非阻塞,当第一个阶段的数据准备好之后,系统需要将数据从kernel复制到用户层,这时候也是阻塞的。

1.3 I/O复用

使用select/poll/epoll等待数据,并且等待多个套接字中的任何一个变为可读。这一过程会被阻塞,当某一个套接字可读的时候返回。之后再调用recvfrom把数据从内核复制到进程中。

这种模式可以让单个进程具有处理多个I/O事件的能力。又被称为Event Driven,即事件驱动I/O。

1.4 信号驱动I/O

应用进程使用sigaction系统调用,内核立即返回,应用进程可以继续执行。也就是等待数据阶段应用进程是非阻塞的。内核在数据到达时向应用进程SIGIO信号,应用进程收到之后在信号处理程序中调用recvfrom将数据从内核复制到应用进程中。相比于非阻塞I/O的轮询方式,信号驱动I/O的CPU效率更高。

1.5 异步I/O。

aio_read系统调用会立即返回,应用进程会继续执行,不会被阻塞,内核会在所有操作完成之后向应用进程发送信号。异步I/O与信号驱动I/O的区别在于,异步IO的信号是通知应用进程I/O完成,而信号驱动I/O的信号是通知应用进程可以开始I/O。

2、同步I/O与异步I/O。

同步I/O:应用进程在调用recvfrom操作时会阻塞

异步I/O:  不会阻塞

3、I/O复用

select/poll/epoll都是IO多路复用的具体体现。select、poll、epoll为三种IO复用方式的出现的顺序。

int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

n为待监测的描述符的总个数加1。readset、writeset、exceptset分别对应读、写、异常事件的描述符集合。fd_set采用数组实现,数组大小使用FD_SETSIZE定义。成功调用返回结果大于0,出错调用返回结果为-1,超时为0。

猜你喜欢

转载自blog.csdn.net/weixin_40825228/article/details/81945938