事件循环和IO多路复用机制介绍 事件循环是`libevent、libev、libuv、libhv`这类网络库里最核心的概念,即在事件循环里处理IO读写事件、定时器事件、自定义事件等各种事件;
IO多路复用即在一个IO线程监听多个fd,如最早期的`select`、后来的`poll`,`linux的epoll`、`windows的iocp`、`bsd的kqueue`、`solaris的port`等,都属于IO多路复用机制。
非阻塞NIO搭配IO多路复用机制就是高并发的钥匙。
`libhv`下的`event`模块正是封装了多种平台的IO多路复用机制,提供了统一的事件接口,是`libhv`的核心模块。
`hloop.h`: 事件循环模块对外头文件。
```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)