socket编程模式生动解释

 很幽默的讲解六种Socket IO模型 看了还是还是有些模糊,libevent的A tiny introduction to asynchronous IO 更清晰。

可以仿照前面那篇写一下,建立的模型更健全点。

假设老陈是服务器端应用程序。

老陈的多个女儿是客户端应用程序。

送信的邮递员是网络。

操作系统式是个信箱管理员。邮递员不能直接投到信箱,是先把信给信箱管理员,信箱管理员再把信放到指定的信箱。

信箱是已经和客户端相连的socket。listen的socket想不到好的比喻。

装信的袋子是buffer。每次老陈都是拿一袋子的。


刚开始女儿没给老陈寄信,信箱管理员对老陈说有女儿可能要开始给你寄信了,老陈就去挂一个信箱(accept)。

传统的单线程阻塞同步

老陈站在信箱A旁,等信箱管理员把信放入信箱A时,再一封封放入袋子,然后拿走。

再到下一个信箱B等着。

如果信箱管理员把信先放到B了而没放入A,老陈也还是在信箱A等着,不会先去看B。

多线程阻塞同步

老陈有好几个老婆。多一个女儿开始准备寄信,老陈就多挂一个信箱。同时老陈自己是不看信箱的,会叫来一个老婆看着守信。

这样效率比单线程阻塞高,但叫老婆要开销,而且老婆可能不够女儿多。

单线程非阻塞同步

老陈不停轮询检查每个邮箱是否有新的信,有就装到袋子里然后拿去处理。没有就马上跳过,而不是像阻塞那样,一直待在那个信箱等到有信为止。

处理完一个邮箱再到下一个邮箱。

Select同步(阻塞的)

一直不停检查邮箱老陈要累死了,老陈发现其实信箱管理员是知道什么时候来信的,于是和信箱管理员商量了一个计划。

老陈一直在信箱旁很清闲得等着(阻塞,但是这个阻塞的线程就没循环检查的CPU开销了),信箱管理员从邮递员那里拿到老陈的信时就通知老陈有信来了。

老陈再去轮询检查一遍所有信箱是否有新的信来了,哪个信箱有信就一封封放到袋子里拿走。

select一个线程最多管理64个socket,要实现多于64个必须通过多个线程。

WSAAsyncSelect异步

WSAAsyncSelect模型的使用

老陈本来是一直在信箱旁很清闲得等着,现在老陈可以去做其他事了,信箱管理员在有信的时候把老陈叫回来收信。

通过窗口消息循环实现异步,跟IOCP类似,但是邮箱管理员不会自己把信放袋子里,还是在用户代码中同步recv send。

因为是基于select实现,一个线程也只能管理64个socket。


WSAEventSelect异步

WSAEventSelect 模型的实现

跟WSAAsyncSelect类似,但是不是通过消息实现,而是通过事件对象。

因为是基于select实现,一个线程也只能管理64个socket。


Epoll同步(阻塞的)

epoll

老陈发现其实信箱管理员除了知道什么时候来信,还知道哪个信箱来信了。

老陈一直在邮箱旁很清闲得等着,信箱管理员从邮递员那里拿到老陈的信时就通知老陈有信来了,同时还告诉老陈是哪个信箱有信或可以发信(即哪个邮箱可进行什么操作都具体告诉了老陈)。

老陈不用检查每个邮箱了,只要对有效的邮箱进行相应的操作就行了。

无64个socket限制。

IOCP异步

老陈发现自己把信一封封放袋子很烦,于是把袋子(读的话空袋子,写的话装满信的袋子)也给了信箱管理员,同时告诉管理员要对袋子里的信进行什么操作。

如果是读操作信箱管理员把信都放到袋子后,再执行老陈之前所告诉他的操作就好了,没老陈啥事儿了。

无64个socket限制。


网络框架

linux的epoll没有windows的iocp,而且除了这两个其他系统用的高效网络实现也都不一样,比如BSD的kqueue,solaris的dev/poll。

于是写跨系统的程序时需要用网络框架,如Libevent、boost.asio等。

大部分都是同步读写接口,就是管理员不会把信装袋子的;只有windows的是异步的。

于是这些框架的异步编程都是模拟的,通过框架模拟邮箱管理员把信放到一个袋子。




IO - 同步,异步,阻塞,非阻塞 (亡羊补牢篇)  Stevens在文章中一共比较了五种IO Model:
a.阻塞型 IO(blocking I/O) 只调用recv和send
b.非阻塞性IO(nonblocking I/O) 只调用recv和send
c.IO多路复用(I/O multiplexing)  select, epoll后,调用调用recv和send
d.信号驱动IO(signal driven I/O)  有windows的WSAAsyncSelect和WSAEventSelect,等状态检查阶段变化信号触发后调用recv和send
e.异步IO(asynchronous I/O)  不用调用recv和send



recv和send这两个个接口,都需经过状态检查阶段和IO阶段。同步异步,阻塞非阻塞 也就体现在这两个阶段:

1.状态检查阶段:检查socket的状态是否改变为可读写等。(等待数据准备好,也就是从网络接收到数据放到内核缓冲区)

一、同步异步:abc都同步的,de是异步的。

二、阻塞非阻塞: ac是阻塞的,b是非阻塞的,de由于是异步的没有主动去检测(内核搞定)。

2.IO阶段:rece、send读写数据。(将数据从内核缓冲区复制到用户进程缓冲区)

一、同步异步:abcd都是同步的,只有e是异步的。

一、阻塞非阻塞:a是阻塞,b是非阻塞,cd因为已经经过状态检查阶段确认有数据的所以无所谓阻塞非阻塞,e因为IO是异步的没有主动去IO(内核搞定)。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值