代码拉取完成,页面将自动刷新
LIB-ZC 异步 IO 开发框架, 基于 epoll 实现, 支持 IO 事件, IO 读写(支持SSL), 定时器
首先说明, 可以创建多个运行环境, 每个运行环境独占用一个线程
zaio_base_t * aiobase = zaio_base_create();
举例: 监听端口 fd 是不是可读(比如有connect请求)
先根据 fd 创建一个 IO事件 ev
zaio_t *ev = zaio_create(fd, aiobase);
再设置: 可读的时候执行执行函数 before_accept
void before_accept(zaio_t * ev);
zaio_readable(ev, before_accept);
zaio_readable 立即返回
zaio_base_run(aiobase, 0);
zaio_base_run 阻塞运行
zaio_base_free(aiobase);
/* 监听 0:8899 */
int fd = zlisten("0:8899", 0, 5);
/* 设置: fd 非阻塞 */
znonblocking(fd, 1);
/* 创建: IO事件 */
zaio_t *ev = zaio_create(fd, aiobase);
/* 设置: 监听可读 */
zaio_readable(ev, before_accept);
static void before_accept(zaio_t * ev)
{
/* 获取 ev 绑定的 fd
int sock = zaio_get_fd(ev);
/* 注意: 这个 sock 是非阻塞的 */
int fd = zinet_accept(sock);
if (fd < 0) {
return;
}
/* 上面的 fd 是阻塞的 */
/* 再创建一个IO事件 */
zaio_t *nev = zaio_create(fd, aiobase);
/* 设置: 如果 fd 可读则回调执行 do_echo */
zaio_readable(nev, do_echo);
}
static void do_echo(zaio_t *ev)
{
int fd= zaio_get_fd(ev);
/* 注意: 此 fd 可能可读, 也可能有异常了 */
/* 题外话: 因为 fclose 会关闭 fd, 所以通过 dup(fd) 生成了新的文件描述符 */
FILE *fp = fdopen(dup(fd), "a+");
char buf[1024000+1];
/* 阻塞读一行 */
fgets(buf, 1024000, fp);
/* 阻塞写回去 */
fputs(buf, fp);
fclose(fp);
/* 继续, 有好几种选择 */
if (1) {
/* 可读时, 执行 do_echo */
zaio_readable(ev, do_echo);
return;
}
if (0) {
/* 或 可写时, 执行 do_write
zaio_write_able(ev, do_write); */
return;
}
if (0) {
/* 或者暂停, 则禁用 ev */
zaio_disable(ev);
return;
}
if (0) {
/* 或者, 终止 */
zaio_free(ev, 1);
return;
}
if (0) {
/* 或者, 其他业务 */
/* 不关闭 fd, 只释放 ev 本身资源, 其他业务继续操作 fd */
zaio_free(ev, 0);
return;
}
}
参考 "异步 IO事件"
static void before_accept(zaio_t * ev)
{
int sock = zaio_get_fd(ev);
int fd = zinet_accept(sock);
if (fd < 0) {
return;
}
/* 设置: fd 为 非阻塞 模式 */
znonblocking(fd, 1);
/* 创建: 异步io */
zaio_t aio = zaio_create(fd, aiobase);
/* 为了方便演示, 这里假设, 一行的长度不超过10240 */
/* 设置: 读一行, 最多读取10240个字节后, 执行回调函数 after_read */
zaio_gets(aio, 10240, after_read);
}
static void after_read(zaio_t * aio)
{
int ret = zaio_get_result(aio);
if (ret < 1) {
/* 错, 释放 aio, 并 close(aio的fd) */
zaio_free(aio, 1);
return;
}
zbuf_t *buf = zbuf_create(10240);
/* 把上次读取的行数据保存到 buf, 除了下面函数, 还请参考 zaio_fetch_rbuf */
zaio_get_read_cache(aio, buf, ret);
/* 写字符串到缓存 */
zaio_cache_puts(aio, "your input: ");
/* 写固定长度数据到缓存*/
zaio_cache_write(aio, buf, ret);
/* 刷缓存的数据, 写完后执行 after_write */
zaio_cache_flush(aio, after_write);
zbuf_free(buf);
}
static void after_write(zaio_t * aio)
{
int ret = zaio_get_result(aio);
if (ret < 1) {
/* 错, 释放 aio, 并 close(aio的fd) */
zaio_free(aio, 1);
return;
}
/* 这个时候, 回显已经完成, 继续读客户端数据 */
zaio_gets(aio, 10240, after_read);
}
接上节, 假设 0:8899 是 ssl 端口
static void before_accept(zaio_t * ev)
{
int sock = zaio_get_fd(ev);
int fd = zinet_accept(sock);
if (fd < -1) {
return;
}
/* 设置: fd 为 非阻塞 模式 */
znonblocking(fd, 1);
/* 创建: 异步io */
zaio_t aio = zaio_create(fd, aiobase);
/* 设置: 完成 SSL accept 后, 执行 after_ssl_accept */
zaio_tls_accept(aio, sslctx, after_ssl_accept);
/* 上一行代码中的 sslctx 是 openssl的 SSL_CTX * */
}
static void after_ssl_accept(zaio_t * aio)
{
int ret = zaio_get_result(aio);
if (ret < 1) {
/* 错, (SSL accept 失败), 释放 aio, 并 close(aio的fd) */
zaio_free(aio, 1);
return;
}
/* 这个时候, SSL 握手成功; 此后, 逻辑上, 代码和上节相同 */
zaio_gets(aio, 10240, after_read);
}
参考 "框架一般模型" 部分
zaio_t *tm;
tm = zaio_create(-1, aiobase);
/* 1 秒后执行函数 foo1 */
zaio_sleep(tm, foo1, 1);
/* 10 秒后执行函数 foo2 */
zaio_sleep(zaio_create(-1, aiobase), foo2, 10);
foo1 的实现
static void foo1(zaio_t *zt)
{
/* 此时, 定时器的注册函数已经注销 */
printf(stderr, "%s\n", "log1....................");
/* 再次注册, 1 秒后执行函数 foo1 */
zaio_sleep(zt, foo1, 1);
}
foo2 的实现
static void foo2(zaio_t *zt)
{
printf(stderr, "%s\n", "log2....................");
/* 执行一次就释放这个 timer */
zaio_free(zt);
}
如果希望在其他线程操作 aio:
前提是: 每次(注意:是每次)执行aio(zaio_t *)的一个回调函数后, 执行:
zaio_disable(aio);
之后就可以可以在其他线程操作了
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。