|
May
10
|
整个传输层被抽象成为transport, 简写成xprt, 程序中一般只有一个实例. xprt使用时有两个重要的方法, 一般在主循环中使用:
1 2 3 4 5 | /* 等待一条就绪的连接(新连接, 已断开, 读取完报文). */ struct link *xprt_wait(struct xprt *xprt); /* 传输层接受一条连接. */ int xprt_accept(struct xprt *xprt, struct link *link); |
连接(link)是socket的封装, 所以会有多个实例. link有两个方法:
1 2 3 4 5 | /* 在连接读就绪后(LINK_FLAG_IN)调用, 从连接的接收缓冲中读取报文. */ int link_recv(struct link *link, struct packet *pkt); /* 发送一个报文, 返回已发送(也可能仅仅是拷贝到发送缓冲)的字节数. */ int link_send(struct link *link, struct packet *pkt); |
底层网络IO被包装成fdevent, 接口借鉴epoll, 目前封装了select和epoll, 更多的IO多路复用方式会被支持. 接口如下:
1 2 3 4 5 6 7 8 9 10 11 | /* 添加文件描述符要监听的事件. */ int fdevents_add(struct fdevents *evs, struct fdevent *ev); /* 删除文件描述符要监听的事件. */ int fdevents_del(struct fdevents *evs, struct fdevent *ev); /* 修改文件描述符要监听的事件. */ int fdevents_mod(struct fdevents *evs, struct fdevent *ev); /* 等待监听队列监听的事件, 返回就绪的文件描述符数目. */ int fdevents_wait(struct fdevents *evs, int timeout_ms); |
select方式的接口实现在文件”fdevent_select.c”中, epoll方式的接口实现在文件”fdevent_epoll.c”中. 编译时, 不需要直接编译这些文件, 而编译一个入口文件”fdevent.c”, 该文件通过编译参数包含相应的实现方式. “fdevent.c”的代码如下(非常简单粗暴, 不用复杂的结构体函数指针成员):
1 2 3 4 5 6 7 8 9 | #include "fdevent.h" #ifdef FDEVENT_USE_EPOLL # include "fdevent_epoll.c" #endif #ifdef FDEVENT_USE_SELECT # include "fdevent_select.c" #endif |
一个使用本网络传输层封闭的echo server(必须使用特定报文)的实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /* 主循环 */ while(1){ link = xprt_wait(xprt); if(link->flags & LINK_FLAG_NEW){ /* 新连接, 接受它 */ xprt_accept(xprt, link); } if(link->flags & LINK_FLAG_DOWN){ /* 得到传输层通知, 连接被关闭, 什么也不做 */ } if(link->flags & LINK_FLAG_IN){ /* 收到一个报文, 然后echo回去 */ link_recv(link, &pkt); link_send(link, &pkt); } } |

Recent Comments