云风在12年写了段代码,讲的是socket server开启一个tcp服务,自己维护一个内存ringbuffer,然后利用epoll/kevent来poll request,自己维护循环收集请求.他的原始代码在此处.
最近抽空看了下代码,发现颇有可观之处,然后就改写下收集到我的工具库里面去.代码可以参考这里
代码的核心思想是检查系统,将BSD的kqueue和Linux的epoll包装成统一的一组api,以供调用.
在具体实现的时候,我们可以看到它有很多好玩的地方,ringbuffer里面的map实现就不细说,我copy来的里面有个隐藏的链表.在初始化的时候,开辟一个连接数组,每个element的fd都是指向下一个的offset,最后一个指向的是-1.再初始化一个头,指向的是0.
每次取连接的时候,都是从头部获得offset,然后将头更新为offset的fd的值.每次还的时候,则是将将要还的的fd改成头的值,再把头更新为将要还的的offset.若头指向-1,则表示没有空的位置.
不过,kquque和epoll只能包括linux和bsd,windows服务下是无法用的,若哪天有兴趣,我打算把select也加上,这样就可以在任何地方都能用了.此外,ringbuffer其实也是个很好的概念,等我有空把rb搞清楚了,也把它补上.
附上调用示例:
// Copyright 2014 Yu Jing <yu@argcv.com> #include <cstdio> #include <unistd.h> #include "argcv/nio/tcp_listen.hh" using namespace argcv::nio; int main(int argc, char * argv[]) { tcp_listen pool(9527, 200000); if (pool._error_no() != 0) { printf("pool establish failed .. %d \n", pool._error_no()); } else { printf("pool established .. %d \n", pool._error_no()); for (;;) { int id = pool.poll(0); if (id != -1) { printf("#### id: %d\n", id); co_lacus::conn &c = pool[id]; bool st = pool.pull(id, 1); if (st) { // printf("data:[%s] %lu \n",c.to_str().c_str(), c.to_str().length()); std::string s = c.to_str(); for (size_t i = 0; i < c.to_str().length(); i++) { printf("%lu %d %c\n", i, c.to_str()[i], c.to_str()[i]); } // sleep(3); c.write(c.to_str(), c.to_str().length()); } else { if (c.closed()) { printf("is closed .. \n"); } else { printf("unknown error ? \n status : %hhu\n", c._status()); } } c.flush(); } } } }
1 Comment