I/O模型

在服务器编程中用到了IO模型,在这里做一下笔记,笔记参考于《Linux高性能服务器编程》

1 I/O模型

socket在创建的时候默认是阻塞。我们可以通过fctnl系统调用来将socket的属性改为非阻塞。阻塞和非阻塞的概念能应用于所有文件描述符,而不仅仅是socket。我们称阻塞的文件描述符为阻塞I/O,非阻塞的文件描述符为非阻塞I/O。

1.1 阻塞I/O

针对阻塞I/O执行的系统调用可能因为无法立即完成而被操作系统挂起,直到等待的事件发生为止。比如,客户端通过connect向服务器发起连接时,connect将首先发送同步报文段给服务器,然后等待服务器返回确认报文段,如果服务器的确认报文段没有立即到达客户端,则connect调用将被挂起【就是tcp三次握手】,直到客户端收到确认报文段并唤醒connect调用。socket的基础API中,可能被阻塞的系统调用包括:accept、read、write、connect。

1.2 非阻塞I/O

针对于非阻塞I/O执行的系统调用则总是立即返回,而不管时间是否已经发生。如果事件没有立即发生,这些系统调用就返回-1,和出错的情况一样。此时我们就必须根据errno来区分这两种情况【原来是这样!!】。对于accept、read、write而言,事件未发生时errno被设置为EAGAIN(意味着再来一次)或者EWOULDBLOCK(意为期望阻塞);对connect而言,errno被设置为EINPROGRESS(意为在处理中)。在我们的代码中,这部分判断可体现为【仅供参考】:

if (errno == EAGAIN || errno == EWOULDBLOCK){
	std::cout << "read later" << endl; // 此时没有读事件
	break; // 跳出ET循环,因为没有事件
} else {
	close(sockfd);
	break;
}

但以上这部分,在我的webserver中哪里可以体现呢?

1.3 非阻塞I/O的使用

很显然,只有在事件已经发生的情况下操作非阻塞I/O(读、写等),才能提高程序的效率。因此,非阻塞I/O通常要和其他I/O通知机制一起使用,比如I/O复用

1.3.1 I/O复用

I/O复用是最常见的I/O通知机制。它指的是,应用程序通过I/O复用函数向内核注册一组事件,内核通过I/O复用函数把其中就绪的事件通知给应用程序。Linux上常用的I/O复用函数有:select、poll、epoll。这里需要指出,I/O复用函数本身就是阻塞的,它们能提高程序效率的原因在于它们具有同时监听多个I/O事件的能力。也就是说,用阻塞的IO通知机制来对非阻塞的IO进行读写操作

IO复用的更多内容见《Linux高性能编程》第9章【这个epoll讲得非常好!】以及《图解系统》对应章节。

1.4 同步I/O和异步I/O

从理论上说,阻塞I/O、I/O复用都是同步I/O模型,因为在这几种I/O模型中,I/O的读写操作,都是在I/O事件发生之后,由应用程序来完成的。

而对异步I/O而言,用户可以直接对I/O执行读写操作,这些操作告诉内核用户读写缓冲区的位置,以及I/O操作完成之后内核通知应用程序的方式。异步I/O的读写操作总是立即返回,而不论I/O是否是阻塞的,因为真正的读写操作已经由内核接管。

也就是说,同步I/O模型要求用户代码自行执行I/O操作(将数据从内核缓冲区读入用户缓冲区,或将数据从用户缓冲区写入内核缓冲区),而异步I/O机制则由内核来执行I/O操作(数据在内核缓冲区和用户缓冲区之间的移动是由内核在后台完成的)。

我们可以这样认为,同步I/O向应用程序通知的是I/O就绪事件,而异步I/O向应用程序通知的是I/O完成事件。

I/O模型对比如下:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值