首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >libuv之unix域的使用

libuv之unix域的使用

作者头像
theanarkh
发布2020-05-18 23:29:30
9680
发布2020-05-18 23:29:30
举报
文章被收录于专栏:原创分享原创分享原创分享

之前分析了unix域在libuv的基本原理。今天以一个简单的例子看一下如何使用它。本文涉及到一些网络编程的知识,不过文章不打算讲解这些,如果不了解可以先了解一下,或者留言。

void remove_sock(int sig) {
    uv_fs_t req;
    // 删除unix域对应的路径
    uv_fs_unlink(loop, &req, PIPENAME, NULL);
    // 退出进程
    exit(0);
}
int main() {
    loop = uv_default_loop();

    uv_pipe_t server;
    uv_pipe_init(loop, &server, 0);
    // 注册SIGINT信号的信号处理函数是remove_sock
    signal(SIGINT, remove_sock);

    int r;
    // 绑定unix路径到socket
    if ((r = uv_pipe_bind(&server, PIPENAME))) {
        fprintf(stderr, "Bind error %s\n", uv_err_name(r));
        return 1;
    }
    /*
        把unix域对应的文件文件描述符设置为listen状态。
        开启监听请求的到来,连接的最大个数是128。有连接时的回调是on_new_connection
    */
    if ((r = uv_listen((uv_stream_t*) &server, 128, on_new_connection))) {
        fprintf(stderr, "Listen error %s\n", uv_err_name(r));
        return 2;
    }
    // 启动事件循环
    return uv_run(loop, UV_RUN_DEFAULT);
}

对于看过之前的文章或者了解网络编程的同学来说。上面的代码看起来会比较简单。所以就不具体分析。他执行完后就是启动了一个服务。同主机的进程可以访问(连接)他。之前说过unix域的实现和tcp的实现类型。都是基于连接的模式。服务器启动等待连接,客户端去连接。然后服务器逐个摘下连接的节点进行处理。我们从处理连接的函数on_new_connection开始分析整个流程。

// 有连接到来时的回调
void on_new_connection(uv_stream_t *server, int status) {
    // 有连接到来,申请一个结构体表示他
    uv_pipe_t *client = (uv_pipe_t*) malloc(sizeof(uv_pipe_t));
    uv_pipe_init(loop, client, 0);
    // 把accept返回的fd记录到client,client是用于和客户端通信的结构体
    if (uv_accept(server, (uv_stream_t*) client) == 0) {
        /*
            注册读事件,等待客户端发送信息过来,
            alloc_buffer分配内存保存客户端的发送过来的信息,
            echo_read是回调
        */
        uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read);
    }
    else {
        uv_close((uv_handle_t*) client, NULL);
    }
}

分析on_new_connection之前,我们先看一下该函数的执行时机。该函数是在uv__server_io函数中被执行,而uv__server_io是在监听的socket(即listen的那个)有可读事件时触发的回调。我们看看uv__server_io的部分逻辑。

// 有连接到来,进行accept
    err = uv__accept(uv__stream_fd(stream));
    // 保存通信socket对应的文件描述符
    stream->accepted_fd = err;
    /*
        有连接,执行上层回调,connection_cb一般会调用uv_accept消费accepted_fd。
        然后重新注册等待可读事件
    */
    stream->connection_cb(stream, 0);

当有连接到来时,服务器调用uv__accept摘取一个连接节点(实现上,操作系统会返回一个文件描述符,作用类似一个id)。然后把文件描述符保存到accepted_fd字段,接着执行connection_cb回调。就是我们设置的on_new_connection。

uv__stream_fd(stream)是我们启动的服务器对应的文件描述符。stream就是表示服务器的结构体。在unix域里,他实际上是一个uv_pipe_s结构体。uv_stream_s是uv_pipe_s的父类。类似c++的继承。

我们回头看一下on_new_connection的代码。主要逻辑如下。 1 申请一个uv_pipe_t结构体用于保存和客户端通信的信息。 2 执行uv_accept 3 执行uv_read_start开始等待数据的到来,然后读取数据。 我们分析一下2和3。我们看一下uv_accept的主要逻辑。

switch (client->type) {
    case UV_NAMED_PIPE:
      // 设置流的标记,保存文件描述符到流上
      uv__stream_open(
          client,server->accepted_fd,
          UV_HANDLE_READABLE | UV_HANDLE_WRITABLE
      );
}

uv_accept中把刚才accept到的文件描述符保存到client中。这样我们后续就可以通过client和客户端通信。至于uv_read_start,之前在stream的文章中已经分析过。就不再深入分析。我们主要分析echo_read。echo_read在客户端给服务器发送信息时被触发。

void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) {
    // 有数据,则回写
    if (nread > 0) {
        write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t));
        // 指向客户端发送过来的数据
        req->buf = uv_buf_init(buf->base, nread);
        // 回写给客户端,echo_write是写成功后的回调
        uv_write((uv_write_t*) req, client, &req->buf, 1, echo_write);
        return;
    }
    // 没有数据了,关闭
    if (nread < 0) {
        if (nread != UV_EOF)
            fprintf(stderr, "Read error %s\n", uv_err_name(nread));
        // 销毁和客户端通信的结构体,即关闭通信
        uv_close((uv_handle_t*) client, NULL);
    }

    free(buf->base);
}

没有数据的时候,直接销毁和客户端通信的结构体和撤销结构体对应的读写事件。我们主要分析有数据时的处理逻辑。当有数据到来时,服务器调用uv_write对数据进行回写。我们看到uv_write的第二个参数是client。即往client对应的文件描述符中写数据。也就是往客户端写。uv_write的逻辑在stream中已经分析过,所以也不打算深入分析。主要逻辑就是在client对应的stream上写入数据,缓存起来,然后等待可写时,再写到对端。写完成后执行echo_write释放数据占据的内存。这就是使用unix域通信的整个过程。unix域还有一个复杂的应用是涉及到传递文件描述符。即uv_pipe_s的ipc字段。这个后续再开一篇文章分析。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-05-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程杂技 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档