io_uring异步IO

io_uring介绍

io_uring是一个Linux内核的异步I/O框架,它提供了高性能的异步I/O操作,io_uring的目标是通过减少系统调用和上下文切换的开销来提高I/O操作的性能。

在网络编程中,我们通常使用epoll IO多路复用来处理网络IO,然而epoll也并不是异步网络IO,仅仅是内核提供了IO复用机制,epoll回调通知的是数据可以读取或者写入了,具体的读写操作仍然需要用户去做,而不是内核代替完成。

io_uring原理介绍:

kernel_new_features/io_uring/文章/浅析开源项目之io_uring.md at main · 0voice/kernel_new_features · GitHubi

io_uring实现tcp服务器

安装liburing

git clone https://github.com/axboe/liburing.git

./configure

make

make install

代码

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


#define EVENT_ACCEPT   	0
#define EVENT_READ		1
#define EVENT_WRITE		2

#define ENTRIES_LENGTH		1024
#define BUFFER_LENGTH		1024

struct conn_info {
    int fd;
    int event;
    char buf[BUFFER_LENGTH];
};

int init_server(unsigned short port) {	

	int sockfd = socket(AF_INET, SOCK_STREAM, 0);	
	struct sockaddr_in serveraddr;	
	memset(&serveraddr, 0, sizeof(struct sockaddr_in));	
	serveraddr.sin_family = AF_INET;	
	serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);	
	serveraddr.sin_port = htons(port);	

	if (-1 == bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(struct sockaddr))) {		
		perror("bind");		
		return -1;	
	}	

	listen(sockfd, 10);
	
	return sockfd;
}

int set_event_recv(struct io_uring *ring,
				      struct conn_info *info, int flags) {

	struct io_uring_sqe *sqe = io_uring_get_sqe(ring);

    info->event = EVENT_READ;
	io_uring_prep_recv(sqe, info->fd, info->buf, BUFFER_LENGTH, flags);
    io_uring_sqe_set_data(sqe, info);
}

int set_event_send(struct io_uring *ring,
				      struct conn_info *info, size_t len, int flags) {

	struct io_uring_sqe *sqe = io_uring_get_sqe(ring);

    info->event = EVENT_WRITE;
	io_uring_prep_send(sqe, info->fd, info->buf, len, flags);
	io_uring_sqe_set_data(sqe, info);
}

int set_event_accept(struct io_uring *ring, struct conn_info *info, 
                struct sockaddr *addr, socklen_t *addrlen, int flags) {

    struct io_uring_sqe *sqe = io_uring_get_sqe(ring);


    info->event = EVENT_ACCEPT;
    io_uring_prep_accept(sqe, info->fd, (struct sockaddr*)addr, addrlen, flags);
    io_uring_sqe_set_data(sqe, info);
}

int main(int argc, char *argv[]) {

	unsigned short port = 9999;
	int sockfd = init_server(port);

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

	struct io_uring ring;
	io_uring_queue_init_params(ENTRIES_LENGTH, &ring, &params);

	struct sockaddr_in clientaddr;	
	socklen_t len = sizeof(clientaddr);

    struct conn_info *accept_info = malloc(sizeof(struct conn_info));
    memset(accept_info, 0, sizeof(struct conn_info));
    accept_info->fd = sockfd;
    accept_info->event = EVENT_ACCEPT;
    
	set_event_accept(&ring, accept_info, (struct sockaddr*)&clientaddr, &len, 0);

	while (1) {

		io_uring_submit(&ring);

		struct io_uring_cqe *cqe;
		io_uring_wait_cqe(&ring, &cqe);

		struct io_uring_cqe *cqes[128];
		int nready = io_uring_peek_batch_cqe(&ring, cqes, 128);  // epoll_wait

		int i = 0;
		for (i = 0;i < nready;i ++) {

			struct io_uring_cqe *entries = cqes[i];
			struct conn_info *result = io_uring_cqe_get_data(entries);

			if (result->event == EVENT_ACCEPT) {

				set_event_accept(&ring, result, (struct sockaddr*)&clientaddr, &len, 0);
				//printf("set_event_accept\n"); //

				int connfd = entries->res;

                struct conn_info *info = malloc(sizeof(struct conn_info));
                memset(info, 0, sizeof(struct conn_info));
                info->fd = connfd;
				set_event_recv(&ring, info, 0);
				
			} else if (result->event == EVENT_READ) {  //

				int ret = entries->res;
				//printf("set_event_recv ret: %d, %s\n", ret, result->buf); //

				if (ret == 0) {
					close(result->fd);
				} else if (ret > 0) {
					set_event_send(&ring, result, ret, 0);
				}
			}  else if (result->event == EVENT_WRITE) {
  //

				int ret = entries->res;
				//printf("set_event_send ret: %d, %s\n", ret, result->buf);
				set_event_recv(&ring, result, 0);
				
			}
			
		}

		io_uring_cq_advance(&ring, nready);
	}

}


运行环境内核版本:Linux version 5.15.0-119-generic,尽量高点,不然容易报错

测试:客户端建立50个连接,发送1百万个请求,测试QPS

收发包框架\数据包大小641282565121024
io_uring8401282345803088262481752
epoll7414573561738667494072358

 io_uring qps比epoll块10%左右

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值