637 lines
23 KiB
Markdown
637 lines
23 KiB
Markdown
|
事件循环和IO多路复用机制介绍
|
|||
|
|
|||
|
事件循环是`libevent、libev、libuv、libhv`这类网络库里最核心的概念,即在事件循环里处理IO读写事件、定时器事件、自定义事件等各种事件;<br>
|
|||
|
IO多路复用即在一个IO线程监听多个fd,如最早期的`select`、后来的`poll`,`linux的epoll`、`windows的iocp`、`bsd的kqueue`、`solaris的port`等,都属于IO多路复用机制。<br>
|
|||
|
非阻塞NIO搭配IO多路复用机制就是高并发的钥匙。<br>
|
|||
|
`libhv`下的`event`模块正是封装了多种平台的IO多路复用机制,提供了统一的事件接口,是`libhv`的核心模块。<br>
|
|||
|
|
|||
|
`hloop.h`: 事件循环模块对外头文件。<br>
|
|||
|
|
|||
|
```c
|
|||
|
|
|||
|
// 事件结构体
|
|||
|
struct hevent_s {
|
|||
|
hloop_t* loop; // 事件所属循环
|
|||
|
hevent_type_e event_type; // 事件类型
|
|||
|
uint64_t event_id; // 事件ID
|
|||
|
hevent_cb cb; // 事件回调
|
|||
|
void* userdata; // 用户数据
|
|||
|
void* privdata; // 私有数据
|
|||
|
struct hevent_s* pending_next; // 指向下一个事件,用于实现事件队列
|
|||
|
int priority; // 事件优先级
|
|||
|
};
|
|||
|
|
|||
|
// 设置事件ID
|
|||
|
#define hevent_set_id(ev, id) ((hevent_t*)(ev))->event_id = id
|
|||
|
// 设置事件回调
|
|||
|
#define hevent_set_cb(ev, cb) ((hevent_t*)(ev))->cb = cb
|
|||
|
// 设置事件优先级
|
|||
|
#define hevent_set_priority(ev, prio) ((hevent_t*)(ev))->priority = prio
|
|||
|
// 设置事件用户数据
|
|||
|
#define hevent_set_userdata(ev, udata) ((hevent_t*)(ev))->userdata = (void*)udata
|
|||
|
|
|||
|
// 获取事件所属循环
|
|||
|
#define hevent_loop(ev) (((hevent_t*)(ev))->loop)
|
|||
|
// 获取事件类型
|
|||
|
#define hevent_type(ev) (((hevent_t*)(ev))->event_type)
|
|||
|
// 获取事件ID
|
|||
|
#define hevent_id(ev) (((hevent_t*)(ev))->event_id)
|
|||
|
// 获取事件回调
|
|||
|
#define hevent_cb(ev) (((hevent_t*)(ev))->cb)
|
|||
|
// 获取事件优先级
|
|||
|
#define hevent_priority(ev) (((hevent_t*)(ev))->priority)
|
|||
|
// 获取事件用户数据
|
|||
|
#define hevent_userdata(ev) (((hevent_t*)(ev))->userdata)
|
|||
|
|
|||
|
// hidle_t、htimer_t、hio_t皆是继承自hevent_t,继承上面的数据成员和函数方法
|
|||
|
|
|||
|
// 新建事件循环
|
|||
|
hloop_t* hloop_new(int flags DEFAULT(HLOOP_FLAG_AUTO_FREE));
|
|||
|
|
|||
|
// 释放事件循环
|
|||
|
void hloop_free(hloop_t** pp);
|
|||
|
|
|||
|
// 运行事件循环
|
|||
|
int hloop_run(hloop_t* loop);
|
|||
|
|
|||
|
// 停止事件循环
|
|||
|
int hloop_stop(hloop_t* loop);
|
|||
|
|
|||
|
// 暂停事件循环
|
|||
|
int hloop_pause(hloop_t* loop);
|
|||
|
|
|||
|
// 继续事件循环
|
|||
|
int hloop_resume(hloop_t* loop);
|
|||
|
|
|||
|
// 唤醒事件循环
|
|||
|
int hloop_wakeup(hloop_t* loop);
|
|||
|
|
|||
|
// 返回事件循环状态
|
|||
|
hloop_status_e hloop_status(hloop_t* loop);
|
|||
|
|
|||
|
// 更新事件循环里的时间
|
|||
|
void hloop_update_time(hloop_t* loop);
|
|||
|
|
|||
|
// 返回事件循环里记录的时间
|
|||
|
uint64_t hloop_now(hloop_t* loop); // s
|
|||
|
uint64_t hloop_now_ms(hloop_t* loop); // ms
|
|||
|
uint64_t hloop_now_us(hloop_t* loop); // us
|
|||
|
|
|||
|
// 返回事件循环所在进程ID
|
|||
|
long hloop_pid(hloop_t* loop);
|
|||
|
|
|||
|
// 返回事件循环所在线程ID
|
|||
|
long hloop_tid(hloop_t* loop);
|
|||
|
|
|||
|
// 返回事件循环的循环次数
|
|||
|
uint64_t hloop_count(hloop_t* loop);
|
|||
|
|
|||
|
// 返回事件循环里激活的IO事件数量
|
|||
|
uint32_t hloop_nios(hloop_t* loop);
|
|||
|
|
|||
|
// 返回事件循环里激活的定时器事件数量
|
|||
|
uint32_t hloop_ntimers(hloop_t* loop);
|
|||
|
|
|||
|
// 返回事件循环里激活的空闲事件数量
|
|||
|
uint32_t hloop_nidles(hloop_t* loop);
|
|||
|
|
|||
|
// 返回事件循环里激活的事件数量
|
|||
|
uint32_t hloop_nactives(hloop_t* loop);
|
|||
|
|
|||
|
// 设置事件循环的用户数据
|
|||
|
void hloop_set_userdata(hloop_t* loop, void* userdata);
|
|||
|
|
|||
|
// 获取事件循环的用户数据
|
|||
|
void* hloop_userdata(hloop_t* loop);
|
|||
|
|
|||
|
// 投递事件
|
|||
|
void hloop_post_event(hloop_t* loop, hevent_t* ev);
|
|||
|
|
|||
|
// 添加空闲事件
|
|||
|
hidle_t* hidle_add(hloop_t* loop, hidle_cb cb, uint32_t repeat DEFAULT(INFINITE));
|
|||
|
|
|||
|
// 删除空闲事件
|
|||
|
void hidle_del(hidle_t* idle);
|
|||
|
|
|||
|
// 添加超时定时器
|
|||
|
htimer_t* htimer_add(hloop_t* loop, htimer_cb cb, uint32_t timeout_ms, uint32_t repeat DEFAULT(INFINITE));
|
|||
|
|
|||
|
// 添加时间定时器
|
|||
|
htimer_t* htimer_add_period(hloop_t* loop, htimer_cb cb,
|
|||
|
int8_t minute DEFAULT(0), int8_t hour DEFAULT(-1), int8_t day DEFAULT(-1),
|
|||
|
int8_t week DEFAULT(-1), int8_t month DEFAULT(-1), uint32_t repeat DEFAULT(INFINITE));
|
|||
|
|
|||
|
// 删除定时器
|
|||
|
void htimer_del(htimer_t* timer);
|
|||
|
|
|||
|
// 重置定时器
|
|||
|
void htimer_reset(htimer_t* timer, uint32_t timeout_ms DEFAULT(0));
|
|||
|
|
|||
|
// 返回IO多路复用引擎 (select、poll、epoll、etc.)
|
|||
|
const char* hio_engine();
|
|||
|
|
|||
|
// 获取IO对象
|
|||
|
hio_t* hio_get(hloop_t* loop, int fd);
|
|||
|
|
|||
|
// 添加IO读写事件
|
|||
|
int hio_add(hio_t* io, hio_cb cb, int events DEFAULT(HV_READ));
|
|||
|
|
|||
|
// 删除IO读写事件
|
|||
|
int hio_del(hio_t* io, int events DEFAULT(HV_RDWR));
|
|||
|
|
|||
|
// 将IO对象从当前所属事件循环中剥离
|
|||
|
void hio_detach(/*hloop_t* loop,*/ hio_t* io);
|
|||
|
|
|||
|
// 将IO对象关联到新的事件循环
|
|||
|
void hio_attach(hloop_t* loop, hio_t* io);
|
|||
|
|
|||
|
// hio_detach 和 hio_attach 的示例代码见 examples/multi-thread/one-acceptor-multi-workers.c
|
|||
|
/*
|
|||
|
void new_conn_event(hevent_t* ev) {
|
|||
|
hloop_t* loop = ev->loop;
|
|||
|
hio_t* io = (hio_t*)hevent_userdata(ev);
|
|||
|
// 关联到新的worker事件循环
|
|||
|
hio_attach(loop, io);
|
|||
|
}
|
|||
|
|
|||
|
void on_accpet(hio_t* io) {
|
|||
|
// 从acceptor所在事件循环中剥离
|
|||
|
hio_detach(io);
|
|||
|
|
|||
|
// 将新的连接按照负载均衡策略分发到worker线程
|
|||
|
hloop_t* worker_loop = get_one_loop();
|
|||
|
hevent_t ev;
|
|||
|
memset(&ev, 0, sizeof(ev));
|
|||
|
ev.loop = worker_loop;
|
|||
|
ev.cb = new_conn_event;
|
|||
|
ev.userdata = io;
|
|||
|
hloop_post_event(worker_loop, &ev);
|
|||
|
}
|
|||
|
*/
|
|||
|
|
|||
|
// 判断fd是否存在于事件循环
|
|||
|
bool hio_exists(hloop_t* loop, int fd);
|
|||
|
|
|||
|
// 返回一个唯一标示ID
|
|||
|
uint32_t hio_id (hio_t* io);
|
|||
|
|
|||
|
// 返回文件描述符
|
|||
|
int hio_fd (hio_t* io);
|
|||
|
|
|||
|
// 返回错误码
|
|||
|
int hio_error (hio_t* io);
|
|||
|
|
|||
|
// 返回添加的事件
|
|||
|
int hio_events (hio_t* io);
|
|||
|
|
|||
|
// 获取返回的事件
|
|||
|
int hio_revents (hio_t* io);
|
|||
|
|
|||
|
// 返回IO类型
|
|||
|
hio_type_e hio_type (hio_t* io);
|
|||
|
|
|||
|
// 返回本地地址
|
|||
|
struct sockaddr* hio_localaddr(hio_t* io);
|
|||
|
|
|||
|
// 返回对端地址
|
|||
|
struct sockaddr* hio_peeraddr (hio_t* io);
|
|||
|
|
|||
|
// 设置上下文
|
|||
|
void hio_set_context(hio_t* io, void* ctx);
|
|||
|
|
|||
|
// 获取上下文
|
|||
|
void* hio_context(hio_t* io);
|
|||
|
|
|||
|
// 是否已打开
|
|||
|
bool hio_is_opened(hio_t* io);
|
|||
|
|
|||
|
// 是否已连接
|
|||
|
bool hio_is_connected(hio_t* io);
|
|||
|
|
|||
|
// 是否已关闭
|
|||
|
bool hio_is_closed(hio_t* io);
|
|||
|
|
|||
|
// 设置读缓存
|
|||
|
void hio_set_readbuf(hio_t* io, void* buf, size_t len);
|
|||
|
|
|||
|
// 获取读缓存
|
|||
|
hio_readbuf_t* hio_get_readbuf(hio_t* io);
|
|||
|
|
|||
|
// 设置最大读缓存
|
|||
|
void hio_set_max_read_bufsize (hio_t* io, uint32_t size);
|
|||
|
|
|||
|
// 设置最大写缓存
|
|||
|
void hio_set_max_write_bufsize(hio_t* io, uint32_t size);
|
|||
|
|
|||
|
// 获取当前写缓存大小
|
|||
|
size_t hio_write_bufsize(hio_t* io);
|
|||
|
|
|||
|
// 判断是否写完成
|
|||
|
#define hio_write_is_complete(io) (hio_write_bufsize(io) == 0)
|
|||
|
|
|||
|
// 获取最后读的时间
|
|||
|
uint64_t hio_last_read_time(hio_t* io); // ms
|
|||
|
|
|||
|
// 获取最后写的时间
|
|||
|
uint64_t hio_last_write_time(hio_t* io); // ms
|
|||
|
|
|||
|
// 设置accept回调
|
|||
|
void hio_setcb_accept (hio_t* io, haccept_cb accept_cb);
|
|||
|
// 设置连接回调
|
|||
|
void hio_setcb_connect (hio_t* io, hconnect_cb connect_cb);
|
|||
|
// 设置读回调
|
|||
|
void hio_setcb_read (hio_t* io, hread_cb read_cb);
|
|||
|
// 设置写回调
|
|||
|
void hio_setcb_write (hio_t* io, hwrite_cb write_cb);
|
|||
|
// 设置关闭回调
|
|||
|
void hio_setcb_close (hio_t* io, hclose_cb close_cb);
|
|||
|
|
|||
|
// 获取accept回调
|
|||
|
haccept_cb hio_getcb_accept(hio_t* io);
|
|||
|
// 获取连接回调
|
|||
|
hconnect_cb hio_getcb_connect(hio_t* io);
|
|||
|
// 获取读回调
|
|||
|
hread_cb hio_getcb_read(hio_t* io);
|
|||
|
// 获取写回调
|
|||
|
hwrite_cb hio_getcb_write(hio_t* io);
|
|||
|
// 获取关闭回调
|
|||
|
hclose_cb hio_getcb_close(hio_t* io);
|
|||
|
|
|||
|
// 开启SSL/TLS加密通信
|
|||
|
int hio_enable_ssl(hio_t* io);
|
|||
|
// 是否SSL/TLS加密通信
|
|||
|
bool hio_is_ssl(hio_t* io);
|
|||
|
// 设置SSL
|
|||
|
int hio_set_ssl (hio_t* io, hssl_t ssl);
|
|||
|
// 设置SSL_CTX
|
|||
|
int hio_set_ssl_ctx(hio_t* io, hssl_ctx_t ssl_ctx);
|
|||
|
// 新建SSL_CTX
|
|||
|
int hio_new_ssl_ctx(hio_t* io, hssl_ctx_opt_t* opt);
|
|||
|
// 获取SSL
|
|||
|
hssl_t hio_get_ssl(hio_t* io);
|
|||
|
// 获取SSL_CTX
|
|||
|
hssl_ctx_t hio_get_ssl_ctx(hio_t* io);
|
|||
|
// 设置主机名
|
|||
|
int hio_set_hostname(hio_t* io, const char* hostname);
|
|||
|
// 获取主机名
|
|||
|
const char* hio_get_hostname(hio_t* io);
|
|||
|
|
|||
|
// 设置连接超时
|
|||
|
void hio_set_connect_timeout(hio_t* io, int timeout_ms DEFAULT(HIO_DEFAULT_CONNECT_TIMEOUT));
|
|||
|
// 设置关闭超时 (说明:非阻塞写队列非空时,需要等待写完成再关闭)
|
|||
|
void hio_set_close_timeout(hio_t* io, int timeout_ms DEFAULT(HIO_DEFAULT_CLOSE_TIMEOUT));
|
|||
|
// 设置读超时 (一段时间没有数据到来便自动关闭连接)
|
|||
|
void hio_set_read_timeout(hio_t* io, int timeout_ms);
|
|||
|
// 设置写超时 (一段时间没有数据发送便自动关闭连接)
|
|||
|
void hio_set_write_timeout(hio_t* io, int timeout_ms);
|
|||
|
// 设置keepalive超时 (一段时间没有数据收发便自动关闭连接)
|
|||
|
void hio_set_keepalive_timeout(hio_t* io, int timeout_ms DEFAULT(HIO_DEFAULT_KEEPALIVE_TIMEOUT));
|
|||
|
|
|||
|
// 设置心跳 (定时发送心跳包)
|
|||
|
typedef void (*hio_send_heartbeat_fn)(hio_t* io);
|
|||
|
void hio_set_heartbeat(hio_t* io, int interval_ms, hio_send_heartbeat_fn fn);
|
|||
|
|
|||
|
// 接收连接
|
|||
|
// hio_add(io, HV_READ) => accept => haccept_cb
|
|||
|
int hio_accept (hio_t* io);
|
|||
|
|
|||
|
// 连接
|
|||
|
// connect => hio_add(io, HV_WRITE) => hconnect_cb
|
|||
|
int hio_connect(hio_t* io);
|
|||
|
|
|||
|
// 读
|
|||
|
// hio_add(io, HV_READ) => read => hread_cb
|
|||
|
int hio_read (hio_t* io);
|
|||
|
|
|||
|
// 开始读
|
|||
|
#define hio_read_start(io) hio_read(io)
|
|||
|
|
|||
|
// 停止读
|
|||
|
#define hio_read_stop(io) hio_del(io, HV_READ)
|
|||
|
|
|||
|
// 读一次
|
|||
|
// hio_read_start => hread_cb => hio_read_stop
|
|||
|
int hio_read_once (hio_t* io);
|
|||
|
|
|||
|
// 读取直到指定长度
|
|||
|
// hio_read_once => hread_cb(len)
|
|||
|
int hio_read_until_length(hio_t* io, unsigned int len);
|
|||
|
|
|||
|
// 读取直到遇到分隔符
|
|||
|
// hio_read_once => hread_cb(...delim)
|
|||
|
int hio_read_until_delim (hio_t* io, unsigned char delim);
|
|||
|
|
|||
|
// 读取一行
|
|||
|
#define hio_readline(io) hio_read_until_delim(io, '\n')
|
|||
|
|
|||
|
// 读取字符串
|
|||
|
#define hio_readstring(io) hio_read_until_delim(io, '\0')
|
|||
|
|
|||
|
// 读取N个字节
|
|||
|
#define hio_readbytes(io, len) hio_read_until_length(io, len)
|
|||
|
#define hio_read_until(io, len) hio_read_until_length(io, len)
|
|||
|
|
|||
|
// 写
|
|||
|
// hio_try_write => hio_add(io, HV_WRITE) => write => hwrite_cb
|
|||
|
int hio_write (hio_t* io, const void* buf, size_t len);
|
|||
|
|
|||
|
// 关闭
|
|||
|
// hio_del(io, HV_RDWR) => close => hclose_cb
|
|||
|
int hio_close (hio_t* io);
|
|||
|
|
|||
|
// 异步关闭 (投递一个close事件)
|
|||
|
// NOTE: hloop_post_event(hio_close_event)
|
|||
|
int hio_close_async(hio_t* io);
|
|||
|
|
|||
|
//------------------高等级的接口-------------------------------------------
|
|||
|
// 读
|
|||
|
// hio_get -> hio_set_readbuf -> hio_setcb_read -> hio_read
|
|||
|
hio_t* hread (hloop_t* loop, int fd, void* buf, size_t len, hread_cb read_cb);
|
|||
|
// 写
|
|||
|
// hio_get -> hio_setcb_write -> hio_write
|
|||
|
hio_t* hwrite (hloop_t* loop, int fd, const void* buf, size_t len, hwrite_cb write_cb DEFAULT(NULL));
|
|||
|
// 关闭
|
|||
|
// hio_get -> hio_close
|
|||
|
void hclose (hloop_t* loop, int fd);
|
|||
|
|
|||
|
// tcp
|
|||
|
// 接收连接
|
|||
|
// hio_get -> hio_setcb_accept -> hio_accept
|
|||
|
hio_t* haccept (hloop_t* loop, int listenfd, haccept_cb accept_cb);
|
|||
|
// 连接
|
|||
|
// hio_get -> hio_setcb_connect -> hio_connect
|
|||
|
hio_t* hconnect (hloop_t* loop, int connfd, hconnect_cb connect_cb);
|
|||
|
// 接收
|
|||
|
// hio_get -> hio_set_readbuf -> hio_setcb_read -> hio_read
|
|||
|
hio_t* hrecv (hloop_t* loop, int connfd, void* buf, size_t len, hread_cb read_cb);
|
|||
|
// 发送
|
|||
|
// hio_get -> hio_setcb_write -> hio_write
|
|||
|
hio_t* hsend (hloop_t* loop, int connfd, const void* buf, size_t len, hwrite_cb write_cb DEFAULT(NULL));
|
|||
|
|
|||
|
// udp
|
|||
|
// 设置IO类型
|
|||
|
void hio_set_type(hio_t* io, hio_type_e type);
|
|||
|
// 设置本地地址
|
|||
|
void hio_set_localaddr(hio_t* io, struct sockaddr* addr, int addrlen);
|
|||
|
// 设置对端地址
|
|||
|
void hio_set_peeraddr (hio_t* io, struct sockaddr* addr, int addrlen);
|
|||
|
// 接收
|
|||
|
// hio_get -> hio_set_readbuf -> hio_setcb_read -> hio_read
|
|||
|
hio_t* hrecvfrom (hloop_t* loop, int sockfd, void* buf, size_t len, hread_cb read_cb);
|
|||
|
// 发送
|
|||
|
// hio_get -> hio_setcb_write -> hio_write
|
|||
|
hio_t* hsendto (hloop_t* loop, int sockfd, const void* buf, size_t len, hwrite_cb write_cb DEFAULT(NULL));
|
|||
|
|
|||
|
//-----------------顶层的接口---------------------------------------------
|
|||
|
// 创建socket套接字,返回IO对象
|
|||
|
// @hio_create_socket: socket -> bind -> listen
|
|||
|
// sockaddr_set_ipport -> socket -> hio_get(loop, sockfd) ->
|
|||
|
// side == HIO_SERVER_SIDE ? bind ->
|
|||
|
// type & HIO_TYPE_SOCK_STREAM ? listen ->
|
|||
|
hio_t* hio_create_socket(hloop_t* loop, const char* host, int port,
|
|||
|
hio_type_e type DEFAULT(HIO_TYPE_TCP),
|
|||
|
hio_side_e side DEFAULT(HIO_SERVER_SIDE));
|
|||
|
|
|||
|
// @tcp_server: hio_create_socket(loop, host, port, HIO_TYPE_TCP, HIO_SERVER_SIDE) -> hio_setcb_accept -> hio_accept
|
|||
|
// 创建TCP服务,示例代码见 examples/tcp_echo_server.c
|
|||
|
hio_t* hloop_create_tcp_server (hloop_t* loop, const char* host, int port, haccept_cb accept_cb);
|
|||
|
|
|||
|
// @tcp_client: hio_create_socket(loop, host, port, HIO_TYPE_TCP, HIO_CLIENT_SIDE) -> hio_setcb_connect -> hio_setcb_close -> hio_connect
|
|||
|
// 创建TCP客户端,示例代码见 examples/nc.c
|
|||
|
hio_t* hloop_create_tcp_client (hloop_t* loop, const char* host, int port, hconnect_cb connect_cb, hclose_cb close_cb);
|
|||
|
|
|||
|
// @ssl_server: hio_create_socket(loop, host, port, HIO_TYPE_SSL, HIO_SERVER_SIDE) -> hio_setcb_accept -> hio_accept
|
|||
|
// 创建SSL服务端,示例代码见 examples/tcp_echo_server.c => #define TEST_SSL 1
|
|||
|
hio_t* hloop_create_ssl_server (hloop_t* loop, const char* host, int port, haccept_cb accept_cb);
|
|||
|
|
|||
|
// @ssl_client: hio_create_socket(loop, host, port, HIO_TYPE_SSL, HIO_CLIENT_SIDE) -> hio_setcb_connect -> hio_setcb_close -> hio_connect
|
|||
|
// 创建SSL客户端,示例代码见 examples/nc.c => #define TEST_SSL 1
|
|||
|
hio_t* hloop_create_ssl_client (hloop_t* loop, const char* host, int port, hconnect_cb connect_cb, hclose_cb close_cb);
|
|||
|
|
|||
|
// @udp_server: hio_create_socket(loop, host, port, HIO_TYPE_UDP, HIO_SERVER_SIDE)
|
|||
|
// 创建UDP服务端,示例代码见 examples/udp_echo_server.c
|
|||
|
hio_t* hloop_create_udp_server (hloop_t* loop, const char* host, int port);
|
|||
|
|
|||
|
// @udp_server: hio_create_socket(loop, host, port, HIO_TYPE_UDP, HIO_CLIENT_SIDE)
|
|||
|
// 创建UDP客户端,示例代码见 examples/nc.c
|
|||
|
hio_t* hloop_create_udp_client (hloop_t* loop, const char* host, int port);
|
|||
|
|
|||
|
//-----------------转发---------------------------------------------
|
|||
|
// hio_read(io)
|
|||
|
// hio_read(io->upstream_io)
|
|||
|
void hio_read_upstream(hio_t* io);
|
|||
|
// on_write(io) -> hio_write_is_complete(io) -> hio_read(io->upstream_io)
|
|||
|
void hio_read_upstream_on_write_complete(hio_t* io, const void* buf, int writebytes);
|
|||
|
// hio_write(io->upstream_io, buf, bytes)
|
|||
|
void hio_write_upstream(hio_t* io, void* buf, int bytes);
|
|||
|
// hio_close(io->upstream_io)
|
|||
|
void hio_close_upstream(hio_t* io);
|
|||
|
|
|||
|
// io1->upstream_io = io2;
|
|||
|
// io2->upstream_io = io1;
|
|||
|
// 建立转发,示例代码见 examples/socks5_proxy_server.c
|
|||
|
void hio_setup_upstream(hio_t* io1, hio_t* io2);
|
|||
|
|
|||
|
// @return io->upstream_io
|
|||
|
hio_t* hio_get_upstream(hio_t* io);
|
|||
|
|
|||
|
// @tcp_upstream: hio_create_socket -> hio_setup_upstream -> hio_connect -> on_connect -> hio_read_upstream
|
|||
|
// @return upstream_io
|
|||
|
// 建立TCP转发,示例代码见 examples/tcp_proxy_server.c
|
|||
|
hio_t* hio_setup_tcp_upstream(hio_t* io, const char* host, int port, int ssl DEFAULT(0));
|
|||
|
// 建立SSL转发
|
|||
|
#define hio_setup_ssl_upstream(io, host, port) hio_setup_tcp_upstream(io, host, port, 1)
|
|||
|
|
|||
|
// @udp_upstream: hio_create_socket -> hio_setup_upstream -> hio_read_upstream
|
|||
|
// @return upstream_io
|
|||
|
// 建立UDP转发,示例代码见 examples/udp_proxy_server.c
|
|||
|
hio_t* hio_setup_udp_upstream(hio_t* io, const char* host, int port);
|
|||
|
|
|||
|
//-----------------拆包---------------------------------------------
|
|||
|
// 拆包模式
|
|||
|
typedef enum {
|
|||
|
UNPACK_MODE_NONE = 0,
|
|||
|
UNPACK_BY_FIXED_LENGTH = 1, // 固定长度拆包,不建议
|
|||
|
UNPACK_BY_DELIMITER = 2, // 根据分隔符拆包,适用于文本协议
|
|||
|
UNPACK_BY_LENGTH_FIELD = 3, // 根据头部长度字段拆包,适用于二进制协议
|
|||
|
} unpack_mode_e;
|
|||
|
|
|||
|
// 拆包设置
|
|||
|
typedef struct unpack_setting_s {
|
|||
|
unpack_mode_e mode; // 拆包模式
|
|||
|
unsigned int package_max_length; // 最大的包长
|
|||
|
union {
|
|||
|
// UNPACK_BY_FIXED_LENGTH: 固定长度拆包设置
|
|||
|
struct {
|
|||
|
unsigned int fixed_length; // 固定长度
|
|||
|
};
|
|||
|
// UNPACK_BY_DELIMITER: 分隔符拆包设置
|
|||
|
struct {
|
|||
|
unsigned char delimiter[PACKAGE_MAX_DELIMITER_BYTES]; // 分隔符
|
|||
|
unsigned short delimiter_bytes; // 分隔符所占字节数
|
|||
|
};
|
|||
|
/*
|
|||
|
* UNPACK_BY_LENGTH_FIELD: 头部长度字段拆包设置
|
|||
|
*
|
|||
|
* 包长 = 头部长度 + 数据长度 + 调整长度
|
|||
|
* package_len = head_len + body_len + length_adjustment
|
|||
|
*
|
|||
|
* if (length_field_coding == ENCODE_BY_VARINT) head_len = body_offset + varint_bytes - length_field_bytes;
|
|||
|
* else head_len = body_offset;
|
|||
|
*
|
|||
|
* 注意:头部长度字段的值仅代表数据长度,不包括头部本身长度,
|
|||
|
* 如果你的头部长度字段代表总包长,那么应该将length_adjustment设置为负的头部长度
|
|||
|
* length_field stores body length, exclude head length,
|
|||
|
* if length_field = head_len + body_len, then length_adjustment should be set to -head_len.
|
|||
|
*
|
|||
|
*/
|
|||
|
struct {
|
|||
|
unsigned short body_offset; // 到数据的偏移,通常等于头部长度
|
|||
|
unsigned short length_field_offset; // 长度字段偏移
|
|||
|
unsigned short length_field_bytes; // 长度字段所占字节数
|
|||
|
short length_adjustment; // 调整长度
|
|||
|
unpack_coding_e length_field_coding; // 长度字段编码方式
|
|||
|
};
|
|||
|
};
|
|||
|
} unpack_setting_t;
|
|||
|
|
|||
|
/*
|
|||
|
* 拆包示例代码见 examples/jsonrpc examples/protorpc
|
|||
|
*
|
|||
|
* 注意:多个IO对象的unpack_setting_t可能是一样的,所有hio_t里仅保存了unpack_setting_t的指针,
|
|||
|
* unpack_setting_t的生命周期应该被调用者所保证,不应该使用局部变量。
|
|||
|
*/
|
|||
|
|
|||
|
// 设置拆包
|
|||
|
void hio_set_unpack(hio_t* io, unpack_setting_t* setting);
|
|||
|
// 取消拆包设置
|
|||
|
void hio_unset_unpack(hio_t* io);
|
|||
|
|
|||
|
// 拆包设置示例:
|
|||
|
/*
|
|||
|
|
|||
|
// FTP协议通过\r\n分割符拆包
|
|||
|
unpack_setting_t ftp_unpack_setting;
|
|||
|
memset(&ftp_unpack_setting, 0, sizeof(unpack_setting_t));
|
|||
|
ftp_unpack_setting.package_max_length = DEFAULT_PACKAGE_MAX_LENGTH;
|
|||
|
ftp_unpack_setting.mode = UNPACK_BY_DELIMITER;
|
|||
|
ftp_unpack_setting.delimiter[0] = '\r';
|
|||
|
ftp_unpack_setting.delimiter[1] = '\n';
|
|||
|
ftp_unpack_setting.delimiter_bytes = 2;
|
|||
|
|
|||
|
// MQTT协议通过头部长度字段拆包,头部长度字段使用了varint编码
|
|||
|
unpack_setting_t mqtt_unpack_setting = {
|
|||
|
.mode = UNPACK_BY_LENGTH_FIELD,
|
|||
|
.package_max_length = DEFAULT_PACKAGE_MAX_LENGTH,
|
|||
|
.body_offset = 2,
|
|||
|
.length_field_offset = 1,
|
|||
|
.length_field_bytes = 1,
|
|||
|
.length_field_coding = ENCODE_BY_VARINT,
|
|||
|
};
|
|||
|
|
|||
|
*/
|
|||
|
|
|||
|
//-----------------重连----------------------------------------
|
|||
|
// 重连设置
|
|||
|
typedef struct reconn_setting_s {
|
|||
|
uint32_t min_delay; // ms 重连最小延时
|
|||
|
uint32_t max_delay; // ms 重连最大延时
|
|||
|
uint32_t cur_delay; // ms 当前延时
|
|||
|
/*
|
|||
|
* @delay_policy: 延时策略
|
|||
|
* 0: fixed 固定延时
|
|||
|
* min_delay=3s => 3,3,3...
|
|||
|
* 1: linear 线性增长延时
|
|||
|
* min_delay=3s max_delay=10s => 3,6,9,10,10...
|
|||
|
* other: exponential 指数增长延时
|
|||
|
* min_delay=3s max_delay=60s delay_policy=2 => 3,6,12,24,48,60,60...
|
|||
|
*/
|
|||
|
uint32_t delay_policy; // 延时策略
|
|||
|
uint32_t max_retry_cnt; // 最大重试次数
|
|||
|
uint32_t cur_retry_cnt; // 当前重试次数
|
|||
|
} reconn_setting_t;
|
|||
|
|
|||
|
// 重连设置初始化
|
|||
|
void reconn_setting_init(reconn_setting_t* reconn);
|
|||
|
|
|||
|
// 重连设置重置
|
|||
|
void reconn_setting_reset(reconn_setting_t* reconn);
|
|||
|
|
|||
|
// 增加重试次数并判断是否未超过最大重试次数
|
|||
|
bool reconn_setting_can_retry(reconn_setting_t* reconn);
|
|||
|
|
|||
|
// 计算当前重连延时
|
|||
|
uint32_t reconn_setting_calc_delay(reconn_setting_t* reconn);
|
|||
|
|
|||
|
//-----------------负载均衡-------------------------------------
|
|||
|
// 负载均衡策略枚举
|
|||
|
typedef enum {
|
|||
|
LB_RoundRobin, // 轮询
|
|||
|
LB_Random, // 随机
|
|||
|
LB_LeastConnections,// 最少连接数
|
|||
|
LB_IpHash, // IP hash
|
|||
|
LB_UrlHash, // URL hash
|
|||
|
} load_balance_e;
|
|||
|
|
|||
|
//-----------------可靠UDP---------------------------------------------
|
|||
|
// 关闭可靠UDP
|
|||
|
int hio_close_rudp(hio_t* io, struct sockaddr* peeraddr DEFAULT(NULL));
|
|||
|
|
|||
|
// KCP设置
|
|||
|
typedef struct kcp_setting_s {
|
|||
|
// ikcp_create(conv, ...)
|
|||
|
unsigned int conv;
|
|||
|
// ikcp_nodelay(kcp, nodelay, interval, fastresend, nocwnd)
|
|||
|
int nodelay;
|
|||
|
int interval;
|
|||
|
int fastresend;
|
|||
|
int nocwnd;
|
|||
|
// ikcp_wndsize(kcp, sndwnd, rcvwnd)
|
|||
|
int sndwnd;
|
|||
|
int rcvwnd;
|
|||
|
// ikcp_setmtu(kcp, mtu)
|
|||
|
int mtu;
|
|||
|
// ikcp_update
|
|||
|
int update_interval;
|
|||
|
} kcp_setting_t;
|
|||
|
|
|||
|
// KCP 正常模式
|
|||
|
HV_INLINE void kcp_setting_init_with_normal_mode(kcp_setting_t* setting);
|
|||
|
|
|||
|
// KCP fast模式
|
|||
|
void kcp_setting_init_with_fast_mode(kcp_setting_t* setting);
|
|||
|
|
|||
|
// KCP fast2模式
|
|||
|
void kcp_setting_init_with_fast2_mode(kcp_setting_t* setting);
|
|||
|
|
|||
|
// KCP fast3模式
|
|||
|
void kcp_setting_init_with_fast3_mode(kcp_setting_t* setting);
|
|||
|
|
|||
|
// 设置KCP,示例代码见 examples/udp_echo_server.c => #define TEST_KCP 1
|
|||
|
int hio_set_kcp(hio_t* io, kcp_setting_t* setting DEFAULT(NULL));
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
示例代码:
|
|||
|
|
|||
|
- 事件循环: [examples/hloop_test.c](../../examples/hloop_test.c)
|
|||
|
- 定时器: [examples/htimer_test.c](../../examples/htimer_test.c)
|
|||
|
- TCP回显服务: [examples/tcp_echo_server.c](../../examples/tcp_echo_server.c)
|
|||
|
- TCP聊天服务: [examples/tcp_chat_server.c](../../examples/tcp_chat_server.c)
|
|||
|
- TCP代理服务: [examples/tcp_proxy_server.c](../../examples/tcp_proxy_server.c)
|
|||
|
- TCP客户端: [examples/tcp_client_test.c](../../examples/tcp_client_test.c)
|
|||
|
- UDP回显服务: [examples/udp_echo_server.c](../../examples/udp_echo_server.c)
|
|||
|
- UDP代理服务: [examples/udp_proxy_server.c](../../examples/udp_proxy_server.c)
|
|||
|
- 网络客户端: [examples/nc](../../examples/nc.c)
|
|||
|
- SOCKS5代理服务: [examples/socks5_proxy_server.c](../../examples/socks5_proxy_server.c)
|
|||
|
- HTTP服务: [examples/tinyhttpd.c](../../examples/tinyhttpd.c)
|
|||
|
- HTTP代理服务: [examples/tinyproxyd.c](../../examples/tinyproxyd.c)
|
|||
|
- jsonRPC示例: [examples/jsonrpc](../../examples/jsonrpc)
|
|||
|
- protobufRPC示例: [examples/protorpc](../../examples/protorpc)
|
|||
|
|
|||
|
多进程/多线程模式示例代码:
|
|||
|
|
|||
|
- 多accept进程模式: [examples/multi-thread/multi-acceptor-processes.c](../../examples/multi-thread/multi-acceptor-processes.c)
|
|||
|
- 多accept线程模式: [examples/multi-thread/multi-acceptor-threads.c](../../examples/multi-thread/multi-acceptor-threads.c)
|
|||
|
- 一个accept线程+多worker线程: [examples/multi-thread/one-acceptor-multi-workers.c](../../examples/multi-thread/one-acceptor-multi-workers.c)
|