C/C++培训
达内IT学院
400-996-5531
虽然市面上已经有很多成熟的网络库,但是编写一个自己的网络库依然让我获益匪浅,这篇文章主要包含:TCP 网络库都干了些什么?下面为大家详解一下。
首先,大家都知道操作系统原生的socket都是同步阻塞的,你每调用一次发送接口,线程就会阻塞在那里,直到将数据复制到了发送窗体。那发送窗体满了怎么办,阻塞的 socket 会一直等到有位置了或者超时。你每调用一次接收接口,线程就会阻塞在那里,直到接收窗体收到了数据。同步阻塞的弊端显而易见,上厕所的时候不能玩手机,不是每个人都能受得了。
客户端可以单独建立一个线程一直阻塞等待接收,那服务器每个 socket 都建一个线程阻塞等待岂不悲哉,apache 这么用过,所以有了 Nginx。那能不能创建一个异步的 socket 调用之后直接返回,什么时候执行完了,无论成功还是失败再通知回来,实现所谓 IO 复用?好消息是现在操作系统大都实现了异步 socket,CppNet 中 Windows 上通过 WSASocket 创建异步的 socket,在 Linux 上通过 fcntl 修改 socket 属性添加上 O_NONBLOCK。
有了异步 socket,调用的时候不论成功与否,网络 IO 接口都会立马返回,成功或失败,发送了多少数据,回头再通知你。现在调用是很舒畅,那怎么获取结果通知呢?这在不同操作系统就有了不同的实现。早些年的时候有过 select 和 poll,但是各有各的弊端,这个不是本文重点,在此不再详述。
现在在windows上使用 IOCP,在 Linux 上使用 epoll 做事件触发,基本已经算是共识。有了 IOCP 和 epoll,我们调用网络接口的时候,要把这个过程或者干脆叫做任务,通知给事件触发模型,让操作系统来监控哪个 socket 数据发送完了,哪个 socket 有新数据接收了,然后再通知给我们。到这里,基本实现异步的socket读写该有的东西已经全部备齐。
还有一点不同的是,IOCP 在接收发送数据的时候,会自己默默的干活儿,干完了,再通知给你。你告诉 IOCP 我要发送这些数据,IOCP 就会默默的把这些数据写进发送窗体,然后告诉你说:“ 头儿,我干完了 ” 。你告诉 IOCP 我要读取这个 socket 的数据,IOCP 就会默默的接收这个socket的数据,然后告诉你:“头儿,我给您带过来了”。这就着实让人省心,你甚至不用再去调用 socket 的原生接口 。
epoll 则不同,其内部只是在监测这个socket是否可以发送或读取数据(当然还有建连等),不会像 IOCP 那样把活儿干完了再告诉你。你告诉 epoll 我要监测这个 socket 的发送和读取事件,当事件到来的时候,epoll 不会管怎么干活儿,只会冷淡的敲敲窗户告诉你:”有事儿了,出来干活儿吧“。
IOCP 像是一个懂得讨领导欢心的老油条,epoll 则完全是一个初入职场的毛头小子。这就是 Proactor 和 Reactor 模式的区别。现在客户端就是领导的位置,所以CppNet 实现为一个 Proactor 模式的网络库,让客户端干最少的活儿。ASIO 也实现为 Proactor ,而 libevent 实现为 Reactor 模式 。
我们现在把刚才说的过程总结一下,首先需要把 socket 设置非阻塞,然后不同平台上将事件通知到不同事件触发模型上,监测到事件时,回调通知给上层。这就是一个网络库要有的核心功能,所有其他的东西都是在给这个过程做辅助。
版权声明:转载文章来自公开网络,版权归作者本人所有,推送文章除非无法确认,我们都会注明作者和来源。如果出处有误或侵犯到原作者权益,请与我们联系删除或授权事宜。
填写下面表单即可预约申请免费试听!怕钱不够?可就业挣钱后再付学费! 怕学不会?助教全程陪读,随时解惑!担心就业?一地学习,可全国推荐就业!
Copyright © 京ICP备08000853号-56 京公网安备 11010802029508号 达内时代科技集团有限公司 版权所有
Tedu.cn All Rights Reserved