近期做了个完成度比较高的东西,一个工作中搞出来的网络库. 想通过这次机会弥补一下之前在网路这方面的短板.
设计大概是如下的几个方面:
-
Buffer/Codec/Protocol.
这个模块的功能是实现可中断、可恢复的消息协议解析.可选的功能有基于复制的buffer和基于零拷贝的buffer,这两种buffer搭配encoder和decoder都能实现可中断的消息协议解析.场景主要是,某个fd有数据读,但读的东西并不完整,可能这次解析了一部分,希望在下次这个fd又有数据读的时候,可以在上一次解析的地方继续往下解而不是主动丢弃希望远端重传。
基于零拷贝的buffer其实主要维护了一个引用次数指针,并搭配上writev和readv.
由于需要支持可中断,这里引申出一个bind操作用于将En、Decoder与Buffer相绑定.
-
基于Reactor和异步文件io + poller + job_queue/map的线程模型
很主流的设计.基本参照chenshuo那本书来做的,并在他的思想下,稍微做了一些创新.- 异步文件io包括2种文件,1是pipe. 2是网络socket.
- jobqueue/map包含1种queue + 2种map,
1
是本地任务Queue.2
是fd->写任务Q的map,3
是读fd -> Codec/buffer的map. - 每个线程只有一个poller用于轮询一个[文件、事件]集合(电平触发),基本思路是:
- poller的实现支持3种轮询机制,select/poll/epoll.
- 线程之间通过pipe来互相唤醒(通知)本地任务queue有东西了,被pipe_fd唤醒后就去
1
中取任务来执行. - 假如某个socket poll到了可写事件,就去
2
中拿写任务出来,往socket里面写(writev or write) - 同上,假如某个socket poll到了可读事件,就去
3
中读并decode(可能上次中断的地方继续decode)
-
业务逻辑与核心线程模型的分离:
- 这里广泛采取了回调的方式,在一开始的时候就设定好什么[文件、事件]做什么事,如上面的 可写事件实际上也是一种业务逻辑,由外部定义好,在线程开始之前注册进去.
- 定义了多种类型的回调,有:
- 阶段型回调,在线程的启动/初始化/退出3个阶段可注册回调;
- 事件型回调,事件指的是fd + 可读、可写或其他标记的事件, 可以针对每种事件注册回调;
- 链式回调,就是回调的回调,某个回调被调用时,开始时先做什么回调,在结束后又做什么回调....
。。。待续。。。