libhv之hloop_process_ios源码分析

坚持一个原则:one loop--->one thread---->one io_watcher
事件优先级:timer > io > idle

上一篇文章对hloop源码大概逻辑和思想进行了一个简单的分析,其中主要涉及三类(timer>io>idles)事件处理。下面将对hloop_process_ios事件做一下简单的分析。

int hloop_process_ios(hloop_t* loop, int timeout) {
    // That is to call IO multiplexing function such as select, poll, epoll, etc.
    //iowatcher_poll_events主要针对不同模型下的IO事件处理,代码将根据环境选择其一
    int nevents = iowatcher_poll_events(loop, timeout);
    if (nevents < 0) {
        hlogd("poll_events error=%d", -nevents);
    }
    return nevents < 0 ? 0 : nevents;
}

在这里插入图片描述
下面将以epoll模型为例,对IO进行一个简单的分析。

iowatcher_poll_events总结

  1. epoll_wait检测io事件,如果存在则加入pendding队列,如果不存在则直接返回
int iowatcher_poll_events(hloop_t* loop, int timeout) {
    epoll_ctx_t* epoll_ctx = (epoll_ctx_t*)loop->iowatcher;
    if (epoll_ctx == NULL)  return 0;
    if (epoll_ctx->events.size == 0) return 0;
    //等待io事件,如果存在事件则加入pendding队列,单线程模型
    int nepoll = epoll_wait(epoll_ctx->epfd, epoll_ctx->events.ptr, epoll_ctx->events.size, timeout);
    if (nepoll < 0) {
        if (errno == EINTR) {
            return 0;
        }
        perror("epoll");
        return nepoll;
    }
    if (nepoll == 0) return 0;
    int nevents = 0;
    for (int i = 0; i < epoll_ctx->events.size; ++i) {
        struct epoll_event* ee = epoll_ctx->events.ptr + i;
        int fd = ee->data.fd;
        uint32_t revents = ee->events;
        if (revents) {
            ++nevents;
            hio_t* io = loop->ios.ptr[fd];
            if (io) {
                if (revents & (EPOLLIN | EPOLLHUP | EPOLLERR)) {
                    io->revents |= HV_READ;
                }
                if (revents & (EPOLLOUT | EPOLLHUP | EPOLLERR)) {
                    io->revents |= HV_WRITE;
                }
                //加入pendding队列
                EVENT_PENDING(io);
            }
        }
        if (nevents == nepoll) break;
    }
    return nevents;
}

此时看看epoll.c源码接口

int iowatcher_init(hloop_t* loop);
int iowatcher_cleanup(hloop_t* loop);
int iowatcher_add_event(hloop_t* loop, int fd, int events);
int iowatcher_del_event(hloop_t* loop, int fd, int events);
int iowatcher_poll_events(hloop_t* loop, int timeout);

发现模型接口很简单也很统一:初始化模型,加入事件,检测事件,删除事件,清理模型

1. io模型何时与loop绑定的呢?loop初始化即绑定或者在add_event的时候检测绑定
void hloop_init(hloop_t* loop) {
	.....
	 // 初始化iowatcher
    iowatcher_init(loop);
	......
}

int iowatcher_add_event(hloop_t* loop, int fd, int events) {
    if (loop->iowatcher == NULL) {
        iowatcher_init(loop);
    }
    ......
}
2. fd何时与IO模型绑定的呢?io异步读写的时候进行io模型绑定
//read的时候添加io,
int hio_read (hio_t* io) {
    if (io->closed) {
        hloge("hio_read called but fd[%d] already closed!", io->fd);
        return -1;
    }
    hio_add(io, hio_handle_events, HV_READ);
    if (io->readbuf.tail > io->readbuf.head &&
        io->unpack_setting == NULL &&
        io->read_flags == 0) {
        hio_read_remain(io);
    }
    return 0;
}

//将IO和模型绑定iowatcher_add_event
int hio_add(hio_t* io, hio_cb cb, int events) {
    printd("hio_add fd=%d io->events=%d events=%d\n", io->fd, io->events, events);
#ifdef OS_WIN
    // Windows iowatcher not work on stdio
    if (io->fd < 3) return -1;
#endif
    hloop_t* loop = io->loop;
    if (!io->active) {
        EVENT_ADD(loop, io, cb);
        loop->nios++;
    }

    if (!io->ready) {
        hio_ready(io);
    }

    if (cb) {
        io->cb = (hevent_cb)cb;
    }

    if (!(io->events & events)) {
        iowatcher_add_event(loop, io->fd, events);
        io->events |= events;
    }
    return 0;
}

至此io和loop关联完成。

总结
  1. 代码根据编译选项()选则某一种IO模型
  2. loop在初始化的时候将loop和IO模型绑定,默认创建custom event,即socket
  3. 在fd进行读(hio_read )写(hio_write)的时候将fd添加到IO模型
  4. hloop_process_ios 在IO模型检测(epoll_wait)已经准备就绪的IO事件,并且加入pendding队列。

为了更一步了解io细节,下一步将对hio源码进行讲解分析。

libhv是一个基于C++开发的轻量级网络库,用于处理HTTP请求。可以使用libhv来获取图片数据,并将其转换为base64编码。 以下是使用libhv库获取图片数据并转换为base64的示例代码: ```cpp #include <iostream> #include <fstream> #include <cstring> #include "hloop.h" #include "hsocket.h" #include "hbase64.h" void on_http_request(hloop_t* loop, hsocket_t* client, http_message_t* req) { // 从请求中获取图片URL const char* url = req->uri.full; // 发送HTTP请求获取图片数据 http_client_t* http_client = http_client_new(loop); http_request_t* http_req = http_request_new(url, HTTP_GET, NULL); http_req->on_response = [http_req](http_response_t* res) { if (res->status_code == 200) { // 将获取到的图片数据转换为base64编码 std::string base64_data = base64_encode(res->body.c_str(), res->body.size()); // 保存base64编码结果到文件或进行其他处理 std::ofstream file("image_base64.txt"); file << base64_data; file.close(); // 打印base64编码结果 std::cout << "Base64 data: " << base64_data << std::endl; } else { std::cerr << "Failed to download image: " << res->status_code << std::endl; } http_request_delete(http_req); }; http_client_send(http_client, http_req); } int main() { hloop_t loop; hloop_init(&loop); // 创建HTTP服务器 http_server_t* http_server = http_server_new(&loop); http_server->on_request = on_http_request; // 启动HTTP服务器 const char* host = "0.0.0.0"; int port = 8000; if (http_server_start(http_server, host, port) == 0) { std::cout << "Server running at http://" << host << ":" << port << std::endl; } else { std::cerr << "Failed to start server" << std::endl; return -1; } // 运行事件循环 hloop_run(&loop); // 清理资源 http_server_free(http_server); hloop_free(&loop); return 0; } ``` 上述代码创建了一个基于libhv的HTTP服务器,当收到HTTP请求时,会获取请求中的图片URL,并使用libhv内置的HTTP客户端发送请求来获取图片数据。然后,将获取到的图片数据转换为base64编码,并保存到文件中。 请确保你已经安装了libhv库,并在编译时链接相应的库文件。编译时需要添加"-lhv"参数,例如: ``` g++ main.cpp -o main -lhv ``` 这样就可以编译并运行上述代码来实现使用libhv库获取图片数据并转换为base64了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值