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);
	}
}

Related posts:

  1. IO多路复用接口封装
  2. 网游服务器的架构 – 层次结构
  3. 一种网络通讯二进制数据格式
  4. svc_recv函数实现详解
  5. C语言网络程序惯用法-参数传递

Written by benegg at 2009-05-10 17:02:14 | Views: 3931 | tags:

Leave a Reply

必须登录, 或者浏览器开启JavaScript支持才可以评论!