libuv学习记录

1. uv_tcp_connect 

int uv_tcp_connect(uv_connect_t* req,
                   uv_tcp_t* handle,
                   const struct sockaddr* addr,
                   uv_connect_cb cb)

 

当建立连接后,回调函数on_connect会被调用。回调函数会接收到一个uv_connect_t结构的数据,它的handle指向通信的socket。这点非常重要:

因为你在进行连接前要先准备好uv_tcp_t的socket和uv_connect_t的connect_req:

    uv_tcp_t* socket = (uv_tcp_t*)malloc(sizeof(uv_tcp_t));
    uv_tcp_init(loop, socket);

    uv_connect_t* connect_req = (uv_connect_t*)malloc(sizeof(uv_connect_t));

什么时候释放这两个资源是个问题, 首先官方文档说了,“当连接建立或发生连接错误时进行回调。”,却没说这个返回值干毛用。

测试发现,无论这次连接成功与否,uv_tcp_connet的返回值都是0,这就比较扯淡了。

所以判断连接是否成功,以及资源释放的逻辑都应放在uv_connect_cb的回调中:

void on_connect(uv_connect_t *req, int status) {
    if (status < 0) {
        fprintf(stderr, "connect failed error %s\n", uv_err_name(status));
        free(req);
        return;
    }

    uv_read_start((uv_stream_t*) req->handle, alloc_buffer, on_read);
    free(req);
}

注意,这里只free了req, 原因是:

传到回调函数中的uv_connect_t结构的handle指向了通信的socket,也及你malloc出来的uv_tcp_t*的socket.

如果你再去uv_close((uv_handle_t*)socket,NULL); 会crash的。

 

2. uv_read_start

int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb);
  • 第2个参数为传入的内存申请回调函数,如: 
void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
  buf->base = malloc(suggested_size);
  buf->len = suggested_size;
}

这就意味着这块内存需要你自己维护(在不用时正确释放这块内存)。

  • 第3个参数为有数据到来需要读取的回调函数,从传入流中读取数据。 会多次执行uv_read_cb回调,直到没有更多数据可读取或调用uv_read_stop()为止。如:
void on_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) {
    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);
        free(client);
        return;
    }

    char *data = (char*) malloc(sizeof(char) * (nread+1));
    data[nread] = '\0';
    strncpy(data, buf->base, nread);

    fprintf(stderr, "%s", data);
    free(data);
    free(buf->base);
}

无论这次读取是否发生错误(根据nread判断),都要及时释放申请的buf,为毛发生错误时要释放client值得一思。

 

完整代码(引自官方示例代码):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <uv.h>

uv_loop_t *loop;

void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
  buf->base = malloc(suggested_size);
  buf->len = suggested_size;
}

void on_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) {
    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);
        free(client);
        return;
    }

    char *data = (char*) malloc(sizeof(char) * (nread+1));
    data[nread] = '\0';
    strncpy(data, buf->base, nread);

    fprintf(stderr, "%s", data);
    free(data);
    free(buf->base);
}

void on_connect(uv_connect_t *req, int status) {
    if (status < 0) {
        fprintf(stderr, "connect failed error %s\n", uv_err_name(status));
        free(req);
        return;
    }

    uv_read_start((uv_stream_t*) req->handle, alloc_buffer, on_read);
    free(req);
}

void on_resolved(uv_getaddrinfo_t *resolver, int status, struct addrinfo *res) {
    if (status < 0) {
        fprintf(stderr, "getaddrinfo callback error %s\n", uv_err_name(status));
        return;
    }

    char addr[17] = {'\0'};
    uv_ip4_name((struct sockaddr_in*) res->ai_addr, addr, 16);
    fprintf(stderr, "%s\n", addr);

    uv_connect_t *connect_req = (uv_connect_t*) malloc(sizeof(uv_connect_t));
    uv_tcp_t *socket = (uv_tcp_t*) malloc(sizeof(uv_tcp_t));
    uv_tcp_init(loop, socket);

    uv_tcp_connect(connect_req, socket, (const struct sockaddr*) res->ai_addr, on_connect);

    uv_freeaddrinfo(res);
}

int main() {
    loop = uv_default_loop();

    struct addrinfo hints;
    hints.ai_family = PF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = 0;

    uv_getaddrinfo_t resolver;
    fprintf(stderr, "irc.freenode.net is... ");
    int r = uv_getaddrinfo(loop, &resolver, on_resolved, "irc.freenode.net", "6667", &hints);

    if (r) {
        fprintf(stderr, "getaddrinfo call error %s\n", uv_err_name(r));
        return 1;
    }
    return uv_run(loop, UV_RUN_DEFAULT);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
libhv和libuv都是开源的跨平台网络库,用于处理网络编程中的底层操作。它们的主要功能是封装对操作系统提供的异步IO接口,使开发者能更加方便地编写高性能的网络应用程序。 libhv是基于C语言的网络库,提供了一套简洁易用的API接口。它开发的初衷是为了满足高性能Web服务器的需求,因此在性能和效率方面有很好的表现。它支持多线程、异步IO、定时器、事件派发等功能,可以在处理大量并发连接的场景中保持低延迟和高吞吐量。libhv还能处理HTTP、WebSocket等应用层协议的解析和处理,使开发者能更加专注于业务逻辑的实现。 libuv也是跨平台的网络库,但是与libhv不同的是,libuv更加注重事件驱动的编程模型。它采用了事件循环机制,可以处理大量同时发生的事件,并将事件分发给相应的事件处理器进行处理。libuv的优点在于它的跨平台性和高性能,它的事件循环机制可以充分利用操作系统提供的异步IO接口,使得网络应用程序能在不同的操作系统上实现高度一致的性能。 在使用上,libhv和libuv都可以在不同的操作系统上运行,包括Windows、Linux、macOS等。它们都提供了丰富的API接口,使得开发者能够灵活地处理网络编程中的各种需求。同时,它们都有活跃的开发社区,可以获取到及时的技术支持和更新。 总体来说,libhv和libuv都是优秀的网络库,具有很高的性能和可靠性。它们的出现不仅使网络编程更加容易,也为开发高性能的网络应用提供了很好的选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值