设为首页 加入收藏

TOP

跨平台长连接组件设计及可插拔改造(五)
2018-04-10 06:06:45 】 浏览:893
Tags:台长 连接 组件 设计 改造
; node_recv_cb recv_cb; node_close_cb close_cb; };

在实现文件中实现接口及回调,注意:即使接口或回调内没有额外的操作,仍然需要实现,例如此处的 log_conn_cb 和 log_connect ,否则上一个插件或下一个插件在日志层调用时会中断

/* callback */
void log_conn_cb(dul_node_t *ctx, int status) {
    zim_log_t *log = (zim_log_t *)ctx;
    if (log->pre && log->pre->conn_cb) {
        log->pre->conn_cb(log->pre, status);
    }
}

/* 省略中间直接回调 */

int log_recv_cb(dul_node_t *ctx, void *params, uv_buf_t *buf, ssize_t size) {
    /* 收集接收到的数据 */
    recv_data_from_server(buf->base, params, size);
    
    /* 继续向上一层插件回调接收到的数据 */
    zim_log_t *log = (zim_log_t *)ctx;
    if (log->pre && log->pre->recv_cb) {
        log->pre->recv_cb(log->pre, opcode, buf, size);
    }
    return OK;
}

/* log hanlder */
int log_init(dul_node_t *ctx, map_t params) {
    zim_log_t *log = (zim_log_t *)ctx;
    bzero(log, sizeof(zim_log_t));

    log->init = &log_init;
    log->conn = &log_connect;
    log->write_data = &log_write;
    log->read_data = &log_read;
    log->close = &log_close;
    log->destroy = &log_destroy;
    log->reset = &log_reset;
    log->conn_cb = &log_conn_cb;
    log->write_cb = &log_write_cb;
    log->recv_cb = &log_recv_cb;
    log->close_cb = &log_close_cb;

    return OK;
}

static void log_connect(dul_node_t *ctx) {
    zim_log_t *log = (zim_log_t *)ctx;
    if (log->next && log->next->conn) {
        log->next->host = log->host;
        log->next->port = log->port;
        log->next->conn(log->next);
    }
}

/* 省略中间直接调用 */

static void log_write(dul_node_t *ctx, 
                      const char *payload, 
                      unsigned long long payload_size,
                      void *params) {
    /* 收集发送数据 */
    send_data_to_server(payload, payload_size, params);

    /* 继续往下一层插件写入数据 */
    zim_log_t *log = (zim_log_t *)ctx;
    if (log->next && log->next->write_data) {
        log->next->write_data(log->next, payload, payload_size, flags);
    }                           
}
  • 增加日志初始化函数及修改转移表
LOADER_ALLOC(zim_log, log);
    
void (*oper_func[])(dul_node_t **) = {
    ws_alloc,
    tls_alloc,
    uv_alloc,
    log_alloc,
};

char const *loaders[] = {
    "ws", "tls", "uv", "log"
};
  • 修改插件注册
/* 增加日志前 */
char loaders[] = "ws?path=/!tls!uv";
context_init(c, "127.0.0.1", 443, "", "", "", "", NULL, loaders);

/* 增加日志后 */
char loaders[] = "log!ws?path=/!log!tls!uv";
context_init(c, "127.0.0.1", 443, "", "", "", "", NULL, loaders);

 

我们重新运行程序,就能发现日志功能已经成功的配置上去,能够将接受和发送的数据上报:

总结

回顾一下跨平台长连接组件的设计,我们使用 libuv 和 mbedtls 分别实现 TCP 和 TLS ,参照 WebSocket 协议实现了其握手及数据读写,同时抽象出通信接口及回调,为了和原生层交互,iOS 和 Android 分别采用 runtime 消息发送和 JNI 进行原生方法调用。

但这样的定向设计完全不符合后期可能会有新增协议解析的预期,所以我们进行了插件化改造,其三个核心点是结构体改造双向链表函数指针

我们通过将插件行为抽象出一个结构体,利用双向链表将前后插件绑定在一起,使用函数指针调用具体插件的函数或回调。

这样做的优点是使得插件之间不存在耦合关系,只需保持逻辑顺序上的关系,同时通过修改插件的注册提高了灵活性,使得组件具有可插拔性(冷插拔)。

但在新增组件中我们需要实现所有的接口和回调,如果数量多的话,这还真是一件比较繁琐的事情。

首页 上一页 2 3 4 5 下一页 尾页 5/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Spring 中获取 request 的几种方.. 下一篇Java日志框架:logback详解

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目