传统的 Linux 网络编程依赖 epoll每次 I/O 事件触发后还需要调用 read/write 等系统调用去真正读写数据。每次系统调用都要在用户态和内核态之间切换连接数一高这部分开销就不可忽视。io_uring 是 Linux 5.1 引入的异步 I/O 框架核心思路是把要做的事提交进去等内核做完再来取结果整个过程通过共享内存的环形队列通信能大幅减少系统调用次数。一.核心数据结构io_uring 有两个环形队列SQSubmission Queue提交队列用户把要做的操作accept/recv/send写进这里。CQCompletion Queue完成队列内核做完操作后把结果写进这里用户来取。每个 SQE提交队列条目有一个 user_data 字段可以存任意用户数据内核完成后原封不动地带回 CQE 里这是事件分发的关键。二.整体框架代码整体分为四个部分1.结构体 — conn_info//#defineEVENT_ACCEPT0#defineEVENT_READ1#defineEVENT_WRITE2structconn_info{intfd;//哪个连接intevent;//什么操作};它是贯穿整个程序的数据载体通过 SQE 的 user_data 在提交和完成之间传递上下文。2.初始化包含两部分网络层的 init_server 做 socket/bind/listen以及 io_uring 的队列初始化和首次注册 acceptintinit_server(unsignedshortport){if(port0)return-1;intsockfdsocket(AF_INET,SOCK_STREAM,0);structsockaddr_insockaddr;sockaddr.sin_familyAF_INET;sockaddr.sin_addr.s_addrhtonl(INADDR_ANY);sockaddr.sin_porthtons(port);intretbind(sockfd,(structsockaddr*)sockaddr,sizeof(structsockaddr_in));if(ret-1)return-2;retlisten(sockfd,10);if(ret-1)return-2;returnsockfd;}structio_uringring;structio_uring_paramsparams;memset(params,0,sizeof(params));io_uring_queue_init_params(ENTRIES_LENGTH,ring,params);// 首次挂上 accept等待第一个连接uring_accept(ring,sockfd,(structsockaddr*)clientaddr,len,0);3.执行函数 — 三个操作封装每个函数从 SQ 队列取一个槽位填入操作参数把 conn_info 写进 user_datauring_accept(ring,sockfd,addr,addrlen,flags);uring_recv(ring,fd,buf,len,flags);uring_send(ring,fd,buf,len,flags);4.主循环while 循环:submit → wait_cqe(阻塞等至少1个) → peek_batch_cqe(批量取) → for 遍历 → 按 EVENT 分发调用执行函数 → cq_advance这里有2个关键点1.为什么 accept 用 res 取 fd而 recv/send 用 result.fd呢因为accept 产生新 fd只能从返回值拿而之后的recv/send 是用的已有 fd其早就存进 user_data 了。2.先写wait_cqe 阻塞等至少一个完成保证后面 peek_batch_cqe 进去的时候 CQ 里一定有东西不会空转。三.详细代码#includeliburing.h#includestdio.h#includesys/socket.h#includearpa/inet.h#includestring.h#includeunistd.h#includenetinet/in.h// return -1 -- init error// -2 -- return error#defineEVENT_ACCEPT0#defineEVENT_READ1#defineEVENT_WRITE2#defineENTRIES_LENGTH1024#defineDATA_LENGTH1024structconn_info{intfd;intevent;};intinit_server(unsignedshortport){if(port0)return-1;intsockfdsocket(AF_INET,SOCK_STREAM,0);structsockaddr_insockaddr;sockaddr.sin_familyAF_INET;sockaddr.sin_addr.s_addrhtonl(INADDR_ANY);sockaddr.sin_porthtons(port);intretbind(sockfd,(structsockaddr*)sockaddr,sizeof(structsockaddr_in));if(ret-1)return-2;retlisten(sockfd,10);if(ret-1)return-2;returnsockfd;}inturing_accept(structio_uring*ring,intsockfd,structsockaddr*addr,socklen_t*addrlen,intflags){structio_uring_sqe*sqeio_uring_get_sqe(ring);if(sqeNULL)return-2;io_uring_prep_accept(sqe,sockfd,(structsockaddr*)addr,addrlen,flags);structconn_infoaccept_info{.fdsockfd,.eventEVENT_ACCEPT,};memcpy(sqe-user_data,accept_info,sizeof(structconn_info));return0;}inturing_recv(structio_uring*ring,intfd,void*buf,size_tlen,intflags){structio_uring_sqe*sqeio_uring_get_sqe(ring);if(sqeNULL)return-2;io_uring_prep_recv(sqe,fd,buf,len,flags);structconn_inforecv_info{.fdfd,.eventEVENT_READ,};memcpy(sqe-user_data,recv_info,sizeof(structconn_info));return0;}inturing_send(structio_uring*ring,intfd,constvoid*buf,size_tlen,intflags){structio_uring_sqe*sqeio_uring_get_sqe(ring);if(sqeNULL)return-2;io_uring_prep_send(sqe,fd,buf,len,flags);structconn_infosend_info{.fdfd,.eventEVENT_WRITE,};memcpy(sqe-user_data,send_info,sizeof(structconn_info));return0;}intmain(intargc,charconst*argv[]){unsignedshortport2000;intsockfdinit_server(port);structio_uringring;structio_uring_paramsparams;memset(params,0,sizeof(structio_uring_params));io_uring_queue_init_params(ENTRIES_LENGTH,ring,params);structsockaddr_inclientaddr;socklen_tlensizeof(clientaddr);uring_accept(ring,sockfd,(structsockaddr*)clientaddr,len,0);charbuf[DATA_LENGTH]{0};while(1){io_uring_submit(ring);//触发系统调用内核开始异步 IOstructio_uring_cqe*cqe;io_uring_wait_cqe(ring,cqe);structio_uring_cqe*cqes[512];intnreadyio_uring_peek_batch_cqe(ring,cqes,128);inti0;for(i0;inready;i){structio_uring_cqe*cqecqes[i];structconn_inforesult;memcpy(result,cqe-user_data,sizeof(structconn_info));if(result.eventEVENT_ACCEPT){uring_accept(ring,sockfd,(structsockaddr*)clientaddr,len,0);intconnfdcqe-res;uring_recv(ring,connfd,buf,DATA_LENGTH,0);}elseif(result.eventEVENT_READ){intretcqe-res;if(ret0){close(result.fd);continue;}elseif(ret0){close(result.fd);}else{uring_send(ring,result.fd,buf,DATA_LENGTH,0);printf(send: %d, %s\n,ret,buf);}}elseif(result.eventEVENT_WRITE){uring_recv(ring,result.fd,buf,DATA_LENGTH,0);}}io_uring_cq_advance(ring,nready);}return0;}四.流程图零声社区资源链接https:github.com/0voice