异步I/O操作函数aio_xxx函数

文章目录

  • 前言
  • 异步IO示例
  • 带回调的异步IO
  • 使用aio_read的echo服务
  • 总结


前言

POXSIX提供了用于异步I/O的"aio_xxx"函数集。

名称 功能
aio_read 异步read
aio_write 异步write
aio_fsync 异步fsync
aio_error 获取错误状态
aio_return 获取返回值
aio_cancel 请求取消
aio_suspend 请求等待

异步IO示例

#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char* argv[])
{
    if (argc < 2) return 1;
    struct aiocb cb;
    const struct aiocb* cblist[1];
    char buf[BUFSIZ];
    int fd, n;

    fd = open(argv[1], O_RDONLY);
    if (fd < 0) {
        perror("open");
        exit(EXIT_FAILURE);
    }

    memset(&cb, 0, sizeof(struct aiocb));
    cb.aio_fildes = fd;
    cb.aio_buf = buf;
    cb.aio_nbytes = BUFSIZ-1;

    n = aio_read(&cb);
    if (n < 0) {
        perror("aio_read");
        exit(EXIT_FAILURE);
    }
    cblist[0] = &cb;
    n = aio_suspend(cblist, 1, NULL);
    if (n != 0) {
        perror("aio_read");
        exit(EXIT_FAILURE);
    }
    n = aio_return(&cb);
    if (n < 0) {
        perror("aio_return");
        exit(EXIT_FAILURE);
    }
    buf[n] = '\0';
    printf("%s\n", buf);
    return 0;
}

将aio_read, aio_suspend, aio_return 放在循环中时不能正确读取内容超过缓冲区大小的内容

带回调的异步IO

在回调函数的调用上,有信号和线程两种方式,下面时使用线程进行回调的方式。
如果用SIGEV_THREAD设置回调函数并调用aio_read,从系统内部来看,实际上是用多个线程来实现异步IO。

#include 
// #include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

static void read_done(__sigval_t sigval)
{
    struct aiocb *cb;
    int n;
    cb = (struct aiocb*)(sigval.sival_ptr);
    if (aio_error(cb)  == 0)
    {
        n = aio_return(cb);
        if (n < 0)
        {
            perror("aio_return");
            exit(EXIT_FAILURE);
        }
        printf("%d %d ---\n%.*s", n, cb->aio_nbytes, cb->aio_nbytes, cb->aio_buf);
        exit(EXIT_SUCCESS);
    }
    return;
}

int main(int argc, char* argv[])
{
    if (argc < 2) return 1;
    struct aiocb cb;
    char buf[BUFSIZ] = {'\0'};
    int fd, n;

    fd = open(argv[1], O_RDONLY);
    if (fd < 0) {
        perror("open");
        exit(EXIT_FAILURE);
    }

    memset(&cb, 0, sizeof(struct aiocb));
    cb.aio_fildes = fd;
    cb.aio_buf = buf;
    cb.aio_nbytes = BUFSIZ-1;
    cb.aio_sigevent.sigev_notify = SIGEV_THREAD;
    cb.aio_sigevent.sigev_notify_function = &read_done;
    cb.aio_sigevent.sigev_value.sival_ptr = &cb;

    n = aio_read(&cb);
    if (n < 0) {
        perror("aio_read");
        exit(EXIT_FAILURE);
    }
    
    select(0, NULL, NULL, NULL, NULL);
    return 0;
}

使用aio_read的echo服务

#include 
// #include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

static void read_done(__sigval_t sigval)
{
    struct aiocb *cb;
    int n;
    cb = (struct aiocb*)(sigval.sival_ptr);
    if (aio_error(cb)  == 0)
    {
        n = aio_return(cb);
        if (n < 0)
        {
            perror("aio_return");
            exit(EXIT_FAILURE);
        } else if (0 == n) {
            printf("client %d gone\n", cb->aio_fildes);
            aio_cancel(cb->aio_fildes, cb);
            close(cb->aio_fildes);
            free(cb);
            return;
        }
        printf("client %d (%d)\n", cb->aio_fildes, n);
        write(cb->aio_fildes, cb->aio_buf, n);
        aio_read(cb);
    }
    else
    {
        printf("aio_error\n");
    }
    return;
}
static void register_read(int fd)
{
    struct aiocb *cb;
    char* buf;
    printf("client register %d\n", fd);
    cb = malloc(sizeof(struct aiocb));
    buf = malloc(BUFSIZ);
    memset(cb, 0, sizeof(struct aiocb));
    cb->aio_fildes = fd;
    cb->aio_buf = buf;
    cb->aio_nbytes = BUFSIZ;
    cb->aio_sigevent.sigev_notify = SIGEV_THREAD;
    cb->aio_sigevent.sigev_notify_function = read_done;
    cb->aio_sigevent.sigev_value.__sival_ptr = cb;//
    if (aio_read(cb) != 0)
    {
        perror("aio_read");
        return;
    }
}

int main(int argc, char* argv[])
{
    if (argc < 2) return 1;

    struct sockaddr_in addr;
    int s = socket(PF_INET, SOCK_STREAM, 0);

    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(9999);
    if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
        perror("bind");
        exit(EXIT_FAILURE);
    }
    listen(s, 5);

    for (;;)
    {
        int c = accept(s, NULL, 0);
        if (c < 0) continue;
        register_read(c);
    }

    return 0;
}

总结

你可能感兴趣的:(C,Linux,其它,c语言)