io_uring TCP Server

129 阅读2分钟

开发使用的Linux内核版本

Linux asrock 6.8.0-47-generic #47-Ubuntu SMP PREEMPT_DYNAMIC Fri Sep 27 21:40:26 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

安装库

 sudo apt install liburing-dev

代码如下

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <liburing.h>
#include <string.h>
#include <unistd.h>

#define ENTRIES_LENGTH 4096

enum {
    READ,
    WRITE,
    ACCEPT,
};

struct conninfo {
    int connfd;
    int type;
};

void set_read_event(struct io_uring *ring, int fd,void *buf, size_t len, int flag) {
    struct io_uring_sqe *sqe = io_uring_get_sqe(ring);

    io_uring_prep_recv(sqe, fd, buf, len, flag);

    struct conninfo ci = {
        .connfd = fd,
        .type = READ
    };

    memcpy(&sqe->user_data, &ci, sizeof(struct conninfo));
}

void set_accept_event(struct io_uring *ring, int fd, struct sockaddr* cliaddr, socklen_t *clilen, unsigned flag) {
    struct io_uring_sqe *sqe = io_uring_get_sqe(ring);

    io_uring_prep_accept(sqe, fd, cliaddr, clilen, flag);

    struct conninfo ci = {
        .connfd = fd,
        .type = ACCEPT
    };

    memcpy(&sqe->user_data, &ci, sizeof(struct conninfo));
}

void set_write_event(struct io_uring *ring, int fd,void *buf, size_t len, int flag) {
    struct io_uring_sqe *sqe = io_uring_get_sqe(ring);

    io_uring_prep_send(sqe, fd, buf, len, flag);

    struct conninfo ci = {
        .connfd = fd,
        .type = WRITE
    };

    memcpy(&sqe->user_data, &ci, sizeof(struct conninfo));
}

int main(void) {
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd == -1) return -1;
    struct sockaddr_in servaddr, clientaddr;
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(9999);

    if (-1 == bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) {
        return -2;
    }

    listen(listenfd, 10);

    struct io_uring_params params;
    memset(&params, 0, sizeof(params));

    struct io_uring ring;

    io_uring_queue_init_params(ENTRIES_LENGTH, &ring, &params);

    socklen_t clilen = sizeof(clientaddr);

    set_accept_event(&ring, listenfd, (struct sockaddr*)&clientaddr, &clilen, 0);
    char buffer[1024] = {0};
    while(1) {
        struct io_uring_cqe *cqe;

        io_uring_submit(&ring);

        // int ret = io_uring_wait_cqe(&ring, &cqe);

        struct io_uring_cqe *cqes[10];
        int cquecount = io_uring_peek_batch_cqe(&ring, cqes, 10);

        int i = 0;
        unsigned count = 0;
        for(i = 0; i < cquecount; i++) {
            cqe = cqes[i];
            count++;
            struct conninfo ci;

            memcpy(&ci, &cqe->user_data, sizeof(ci));

            if (ci.type == ACCEPT) {
                int connfd = cqe->res;
                set_read_event(&ring, connfd, buffer, 1024, 0);
            } else if (ci.type == READ) {
                int bytes_read = cqe->res;

                if (bytes_read == 0) {
                    close(ci.connfd);
                } else if(bytes_read < 0) {

                } else {
                    printf("buffer: %s\n", buffer);
                    set_write_event(&ring, ci.connfd, buffer, bytes_read, 0);
                }



            } else if (ci.type == WRITE) {
                set_read_event(&ring, ci.connfd, buffer, 1024, 0);
            }

        }
        io_uring_cq_advance(&ring, count);
    }

    getchar();
    return 0;
}

测试

image.png

image.png