Libevent零基础入门教程:纯Event实现高并发网络编程
本文全程基于原生 event 基础API,无任何复杂高级组件,完全适配新手入门:1. 掌握 event_base 基座、事件循环、资源释放流程;2. 熟练使用 event_new/evtimer_new/evsignal_new 创建各类事件;3. 理解事件驱动、非阻塞 IO、Reactor 核心思想;4. 可独立编写定时器、信号监听、并发TCP服务器。
前言
在 Linux 网络编程中,C10K 高并发问题是新手进阶的必经门槛。传统「阻塞IO+多线程」模型代码简单,但并发能力极差;原生 epoll 多路复用性能强,但代码繁琐、坑极多、不适合新手。
而 Libevent 是一款轻量、开源、跨平台的事件驱动网络库,Redis、Memcached 等知名项目均采用它作为底层网络驱动。
本文完全剔除复杂的 bufferevent 高级用法,只保留最核心、最适合新手的 原生 event 事件体系,遵循「先安装→学API→跑Demo→懂原理→实战避坑」的新手学习逻辑,零基础带你吃透 Libevent 基础,轻松上手异步事件编程。
第一部分:为什么要学 Libevent?
1.1 传统阻塞服务器的致命痛点
新手最开始写的网络程序,基本都是 阻塞 IO + 多线程/多进程 模型:每来一个客户端连接,就开一个线程处理。这种模型代码直观,但高并发场景下缺陷非常明显:
1. 资源上限极低:操作系统线程数量有限,上万并发场景会直接资源耗尽、服务崩溃;
2. CPU 浪费严重:大量线程阻塞等待数据,CPU 频繁上下文切换,真正处理业务的资源极少;
3. 无法应对 C10K 并发:完全不满足后端服务高并发、长连接的业务需求。
C10K:C10K Problem(Client 10000 Problem),单台服务器如何同时稳定支撑 10000 个客户端长连接 的高并发难题,是 Linux 网络编程的经典分水岭。
1.2 Libevent 核心优势
Libevent 是对 Linux epoll、Windows select 等多路复用接口的高级封装,以事件驱动为核心,用单线程即可处理海量并发,完美解决传统模型的痛点。
针对新手,它最大的优势只有三点,好记好用:
1. 屏蔽底层复杂内核:不用手写 epoll 繁琐逻辑,封装成简单 API,降低入门门槛;
2. 事件驱动、非阻塞高并发:无事则休眠、有事则触发,无无效轮询,CPU 利用率极高;
3. 接口统一、极简易学:核心 API 极少,学好 event 一套体系,就能写定时器、信号监听、TCP 服务器。
第二部分:Linux 环境快速安装(Ubuntu/Debian)
新手不推荐源码编译,直接使用 apt 一键安装开发库,零报错、配置省心,适配所有课堂/实战环境。
2.1 一键安装命令
sudo apt update s
udo apt install libevent-dev
2.2 安装验证
安装完成后,可通过以下命令验证库文件、头文件是否正常生成:
# 查看库文件
ls /usr/lib/x86_64-linux-gnu/ | grep libevent
# 查看头文件
ls /usr/include/event2/
能正常查询到文件即安装成功。
2.3 新手编译核心规则(必记)
所有 Libevent 代码编译,必须手动链接库文件,编译指令固定格式:
gcc demo.c -o demo -levent
不加 -levent 必定报未定义引用错误,新手 90% 编译问题都源于此。
第三部分: Libevent 核心 API
Libevent 新手入门,只需要掌握以下核心函数,无多余冗余 API,全部基于原生 event,无 bufferevent。所有函数均给出标准原型+逐句解析+使用场景。
3.1 核心结构体
1. 时间结构体(定时器专用)
struct timeval {
time_t tv_sec; // 秒
suseconds_t tv_usec; // 微秒
};
作用:配合 event_add 设置定时触发时间,所有定时器案例通用。
3.2 事件基座函数(程序核心心脏)
任何一个 Libevent 程序,必须有且仅有一个 event_base。
1. event_base_new —— 创建事件基座
struct event_base *event_base_new(void);
作用:创建事件管理器,统一管理所有 IO事件、定时器事件、信号事件。
解析:内部自动适配 epoll/select,屏蔽系统差异;返回 NULL 代表初始化失败。
2. event_base_dispatch —— 启动事件循环
int event_base_dispatch(struct event_base *base);
作用:阻塞启动死循环,持续监听所有注册事件,事件就绪自动触发回调。
新手重点:不执行此函数,所有事件永远不会触发,程序不会运行。
3. event_base_free —— 释放基座资源
void event_base_free(struct event_base *base);
作用:程序退出时释放基座内存,杜绝内存泄漏。
4. event_base_loopexit —— 优雅退出事件循环
int event_base_loopexit(struct event_base *base, const struct timeval *tv);
作用:安全终止 Libevent 事件循环,退出 event_base_dispatch 阻塞状态,实现程序优雅退出,避免暴力退出导致的资源泄漏、事件错乱问题。
参数逐字解析:
-
base:需要终止的事件基座,与启动循环的base必须一致;
-
tv:延迟退出时间,传入 NULL 代表立即退出事件循环;传入timeval结构体则延迟指定时间后退出。
新手重点说明:
-
该函数是安全退出专用API,不会强制终止正在执行的回调,会等待当前回调执行完毕后再退出循环;
-
推荐用于信号回调、业务结束逻辑,替代粗暴的 exit() 退出,方便统一释放事件、基座资源;
-
调用后仅退出事件循环,不会自动释放 event_base 和 event 资源,需要手动执行 event_free、event_base_free。
3.3 通用事件函数(IO事件核心)
用于创建网络读写、监听等普通 IO 事件,是网络编程核心。
1. event_new —— 通用创建事件
struct event *event_new(struct event_base *base, evutil_socket_t fd,
short events, event_callback_fn cb, void *arg);
参数逐字解析:
-
base:所属事件基座
-
fd:监听的文件描述符,定时器填 -1
-
events:监听事件类型(宏)
-
cb:事件触发后的回调函数
-
arg:回调函数自定义传参
必记事件宏:
-
EV_READ:监听可读事件
-
EV_WRITE:监听可写事件
-
EV_PERSIST:持久化事件(无此宏,事件只触发一次)
作用:初始的事件创建函数,创建一个自定义事件
2. event_add —— 注册监听事件
int event_add(struct event *ev, const struct timeval *tv);
核心逻辑:event_new 只是创建事件,event_add 才是真正开启监听。
参数解析:
- ev:要添加的事件对象(由event_new创建)
- tv:定时超时时间,核心分两种用法:
-
传 NULL:代表永久常驻监听,依靠 IO 就绪、信号触发事件(网络事件、信号事件全部用这种写法);
-
传 timeval 结构体地址:代表定时触发事件,到达指定时间自动触发回调(定时器专用写法)。
-
作用:将事件从“未监听”状态转化为“监听”状态,使其被event_base事件循环核心管理。若指定超时时间,event_base会同时监听事件触发条件和超时信号,确保超时前未触发也能执行回调函数
3. event_free —— 释放事件
void event_free(struct event *ev);
-
ev:手动注册的事件
作用:释放事件内存,避免内存泄漏,释放后事件失效。
3.4 专属快捷事件函数
Libevent 为定时器、信号提供专属创建函数,语法更简单、语义更清晰,替代繁琐的 event_new 写法。
1. evtimer_new —— 专属创建定时器事件
struct event *evtimer_new(struct event_base *base, event_callback_fn cb, void *arg);
等价写法:
event_new(base, -1, EV_PERSIST, cb, arg)
优势:无需手动填 fd 和事件宏,专门用于定时场景,新手零出错。
参数逐字解析:
-
base:事件基座对象,当前所有事件的统一管理者,定时器事件必须挂载在该base下调度;
-
cb:定时器触发的回调函数,事件到期后自动执行,函数格式固定为
event_callback_fn类型; -
arg:自定义参数,会原封不动传递给回调函数,无传参需求时填 NULL。
使用说明:evtimer_new 内部自动填充 fd=-1、事件宏=EV_PERSIST,无需用户手动配置,仅需关注基座、回调、自定义参数。
2. evsignal_new —— 专属创建信号事件
struct event *evsignal_new(struct event_base *base, int signum, event_callback_fn cb, void *arg);
作用:监听系统信号(Ctrl+C、进程终止),实现程序优雅退出。
常用信号:SIGINT(2) 键盘中断信号。
参数逐字解析:
-
base:事件基座对象,当前信号事件的所属调度管理器,必须和事件循环的base一致;
-
signum:需要监听的操作系统信号值,int类型,常用 SIGINT、SIGTERM 等系统信号宏;
-
cb:信号触发回调函数,捕获到对应信号后自动执行,函数格式固定为
event_callback_fn类型; -
arg:自定义传参,原样透传给回调函数,可用于传递全局基座、自定义结构体等,无需求填 NULL。
使用说明:evsignal_new 内部自动封装信号事件专属属性、持久化机制,无需手动添加 EV_PERSIST 宏,默认常驻监听信号。
3.5 必备工具函数
evutil_make_socket_nonblocking —— 设置 fd 非阻塞
int evutil_make_socket_nonblocking(evutil_socket_t fd);
新手必记铁律:Libevent 所有网络 fd 必须设置非阻塞,否则会阻塞事件循环,导致程序卡死、事件不触发。
第四部分:新手入门三大实战 Demo
本章所有案例零 bufferevent、纯原生 event 实现,循序渐进,从定时器→信号监听→TCP服务器,贴合新手学习曲线。
4.1 实战一:定时器事件(最简入门)
功能:每5秒自动触发一次定时任务,直观理解事件驱动逻辑。
#include <event2/event.h>
#include <stdio.h>
// 定时回调函数
void timer_cb(evutil_socket_t fd, short event, void *arg) {
printf("定时器触发:任务执行成功\n");
}
int main() {
// 1. 创建事件基座
struct event_base *base = event_base_new();
// 2. 创建定时器事件
struct event *timer = evtimer_new(base, timer_cb, NULL);
// 3. 设置5秒定时,注册监听
struct timeval tv = {5, 0};
event_add(timer, &tv);
// 4. 启动事件循环
event_base_dispatch(base);
// 资源释放
event_free(timer);
event_base_free(base);
return 0;
}
编译运行:gcc timer.c -o timer -levent && ./timer
核心感悟:事件循环阻塞等待,无轮询空耗,CPU 占用为0,这就是事件驱动的优势。
4.2 实战二:信号监听事件(优雅退出)
功能:监听 Ctrl+C 信号,捕获信号后提示退出,实现优雅终止程序。
#include <event2/event.h>
#include <stdio.h>
#include <signal.h>
// 信号回调函数
void signal_cb(evutil_socket_t fd, short event, void *arg) {
printf("\n捕获 Ctrl+C 信号,程序准备退出!\n");
// 获取事件基座,退出事件循环
struct event_base *base = (struct event_base *)arg;
event_base_loopexit(base, NULL);
}
int main() {
struct event_base *base = event_base_new();
// 创建信号事件:监听 SIGINT
struct event *sig_event = evsignal_new(base, SIGINT, signal_cb, base);
event_add(sig_event, NULL);
printf("程序运行中,按下 Ctrl+C 退出\n");
event_base_dispatch(base);
// 释放资源
event_free(sig_event);
event_base_free(base);
printf("程序正常退出\n");
return 0;
}
4.3 实战三:原生Event实现Echo服务器(核心实战)
纯原生 event 实现 TCP 回声服务器,支持多客户端并发连接,是新手必须吃透的核心案例。
功能:客户端连接服务端、发送任意数据、服务端原样返回数据。
#include <event2/event.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUF_LEN 1024
// 客户端读写回调:处理客户端数据收发
void client_read_cb(evutil_socket_t fd, short event, void *arg) {
char buf[BUF_LEN] = {0};
int len = recv(fd, buf, BUF_LEN, 0);
// 客户端断开/异常,关闭fd
if (len <= 0) {
close(fd);
printf("客户端断开连接\n");
return;
}
printf("收到客户端数据:%s\n", buf);
// 原样回声返回
send(fd, buf, len, 0);
}
// 监听回调:接收新客户端连接
void listen_accept_cb(evutil_socket_t fd, short event, void *arg) {
struct event_base *base = (struct event_base *)arg;
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
// 接受新连接
int client_fd = accept(fd, (struct sockaddr *)&client_addr, &addr_len);
if (client_fd < 0) return;
// 【关键】设置非阻塞
evutil_make_socket_nonblocking(client_fd);
// 为新客户端创建可读事件,持久监听
struct event *client_event = event_new(base, client_fd, EV_READ|EV_PERSIST, client_read_cb, NULL);
event_add(client_event, NULL);
printf("新客户端连接成功\n");
}
int main() {
// 1. 创建事件基座
struct event_base *base = event_base_new();
// 2. 创建监听套接字
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
listen(listen_fd, 5);
// 【关键】设置非阻塞
evutil_make_socket_nonblocking(listen_fd);
// 3. 创建监听事件,监听可读状态
struct event *listen_event = event_new(base, listen_fd, EV_READ|EV_PERSIST, listen_accept_cb, base);
event_add(listen_event, NULL);
printf("Echo服务器启动成功,端口:%d\n", PORT);
event_base_dispatch(base);
// 资源释放
event_free(listen_event);
event_base_free(base);
close(listen_fd);
return 0;
}
测试方式:telnet 127.0.0.1 8080,多窗口连接,支持并发通信。
第五部分:核心原理讲解
5.1 Reactor 事件驱动模型
Libevent 底层核心架构就是标准的 Reactor(反应堆)事件驱动模型,是 Linux 高并发网络编程最经典、最主流的设计模式,也是 Nginx、Redis、Libevent 高性能的根本原因。不同于传统多线程阻塞模型,Reactor 模型采用 单线程监听、事件通知、回调执行业务 的思想,完美解决 C10K 并发瓶颈,下面是逻辑完整剖析。
5.1.1 Reactor 核心设计思想
一句话总结:程序不主动轮询资源、不阻塞等待数据,全程休眠待命,仅当内核检测到事件就绪后,才唤醒程序执行对应业务回调。
它彻底抛弃了「一个连接一个线程」的笨重模式,用一个事件循环线程统一管理成千上万的文件描述符(TCP连接、定时器、信号),极大节省系统资源。
5.1.2 传统阻塞模型 VS Reactor 模型
1. 传统阻塞IO+多线程模型:连接到来 → 创建线程 → 线程阻塞等待数据 → CPU频繁切换线程 → 并发上限极低,无法支撑万级连接。
2. Reactor 事件驱动模型:统一注册所有监听事件 → 线程阻塞等待内核通知 → 事件就绪后分发回调 → 处理完立即回归休眠,无空轮询、无多余线程开销。
5.1.3 Reactor 三大核心角色(完全对应 Libevent 组件)
1. 事件调度器(event_base):Reactor 的核心调度中心,内部封装 epoll,负责统一监听所有 fd、定时、信号事件,阻塞等待内核事件通知,统一分发就绪事件。
2. 事件注册器(event):开发者创建的各类事件对象,包含监听fd、事件类型、回调函数、自定义参数,相当于「注册的任务监听规则」。
3. 事件回调器(callback):事件就绪后的具体业务逻辑,由开发者自定义编写,是真正处理读写、定时、信号逻辑的执行体。
5.1.4 Reactor 完整工作流程
1. 创建 event_base 调度中心,初始化内核多路复用监听;
2. 通过 event_new / evtimer_new / evsignal_new 创建事件,绑定监听规则与回调;
3. 调用 event_add 将事件注册到内核监听队列;
4. event_base_dispatch 启动事件循环,线程阻塞休眠;
5. 内核检测到 IO 就绪、时间到期、信号触发,唤醒事件循环;
6. 框架自动匹配对应事件,执行绑定的回调函数;
7. 回调执行完毕,回归阻塞休眠状态,等待下一次事件。
5.1.5 Reactor 模型为什么能解决 C10K 高并发问题
1. 无线程资源开销:单线程即可管理上万连接,无需创建大量线程,无线程内存占用、无上下文切换损耗;
2. 无空轮询浪费CPU:无事件时线程完全休眠,CPU占用近乎为0,只有事件到来才工作;
3. 内核精准事件通知:epoll 只返回就绪的事件,不会无效遍历所有文件描述符,效率极高;
4. 非阻塞异步处理:事件回调快速执行,不阻塞整体事件循环,支持海量并发连接常驻。
5.1.6 Reactor 总结
Reactor 是单线程串行执行回调模型,所有回调共用同一个事件循环线程。回调函数绝对不能写耗时、阻塞代码(sleep、文件读写、复杂运算、阻塞网络请求),否则会卡住全局事件循环,导致所有定时器、连接、信号全部卡顿失效。
第六部分:高频踩坑指南(纯Event避坑)
汇总新手写原生 event 代码最常见的5个错误,直接规避90%问题:
坑1:网络文件描述符未设置非阻塞(新手最高频致命错误)
详细现象:服务启动无报错,端口正常监听,客户端可以正常连接,但发送数据后服务端无任何响应;偶尔出现单次数据接收成功,后续彻底卡死不动;严重时直接阻塞整个事件循环,所有定时器、信号事件全部失效,CPU 占用极低,程序处于假死状态。
深层原因:Linux 系统默认创建的 socket 文件描述符都是阻塞模式,而 Libevent 基于 epoll 事件驱动模型运行,核心运行机制依赖非阻塞 IO。当 fd 为阻塞模式时,一旦缓冲区无数据,
recv()、accept()等函数会主动阻塞线程,卡住整个唯一的事件循环。事件循环被阻塞后,所有注册的 IO 事件、定时事件、信号事件都会停止调度,导致程序整体失效。
完整解决方案:所有参与 Libevent 监听、读写、连接接收的 socket fd(监听fd、客户端连接fd),创建后必须立即设置非阻塞。统一使用 Libevent 标准工具函数
evutil_make_socket_nonblocking(),无需手动调用 Linux 原生 fcntl,兼容性更强、零出错。在服务端案例中,监听套接字、客户端新连接套接字,都需要单独执行一次非阻塞设置,缺一不可。
坑2:事件未添加 EV_PERSIST 持久化宏,事件单次失效
详细现象:定时器、网络可读事件、信号事件仅能触发第一次,触发完成后彻底失效,程序无报错、无崩溃,但后续不再响应任何事件;定时器只执行一次任务就停止,客户端只能第一次发送数据被正常接收,后续数据服务端完全无响应。
深层原因:这是 Libevent 默认机制导致的新手盲区。Libevent 创建的所有事件,默认都是「一次性临时事件」。当事件被内核触发、回调函数执行完成后,框架会自动将该事件从监听队列中移除并销毁,不会持续监听。如果是需要循环监听的定时任务、持续监听的网络读写事件、常驻的信号监听事件,不开启持久化就会直接失效。
完整解决方案:所有需要循环、持续监听的事件,在创建事件时必须叠加EV_PERSIST 宏。网络监听事件、客户端读写事件、常驻信号事件、循环定时器全部需要开启;仅一次性临时任务可以不使用该宏。搭配写法:
EV_READ|EV_PERSIST、EV_READ|EV_WRITE|EV_PERSIST,宏之间用位或拼接。
坑3:只调用 event_new 创建事件,忘记调用 event_add 注册监听
详细现象:代码编译、运行完全无报错,程序正常启动,无崩溃、无异常退出,但所有事件彻底不触发;定时器不执行、客户端连接无响应、Ctrl+C 无法捕获,程序处于空跑状态,新手完全找不到问题根源。
深层原因:很多新手会混淆「创建事件」和「注册事件」两个步骤。
event_new()/evtimer_new()/evsignal_new()仅仅是在内存中创建事件对象、初始化参数,不会将事件交给内核多路复用模型(epoll)监听。此时事件仅存在于用户态内存中,并未加入事件基座的监听队列,内核无法感知该事件,自然不会触发回调。
完整解决方案:Libevent 所有事件必须遵循两步流程:第一步通过 xxx_new 创建事件对象,第二步调用
event_add()将事件挂载到 event_base 监听队列,注册到内核生效。定时器、信号、IO 事件无例外,缺一不可;定时事件需要在 event_add 传入 timeval 结构体,常驻事件直接传 NULL 即可。
坑4:回调函数内编写耗时、阻塞业务逻辑
详细现象:单客户端通信正常,多客户端并发连接后出现严重卡顿、响应延迟;定时器触发间隔紊乱、不准时;信号响应延迟,需要长按 Ctrl+C 才能退出;极端情况下会出现部分客户端连接直接超时断开。
深层原因:Libevent 默认是单线程事件循环,整个程序所有事件的调度、回调执行,都在同一个主线程中串行执行。事件循环的核心逻辑是「一个回调执行完毕,才会调度下一个事件」。如果在回调函数中写 sleep、循环阻塞、文件IO、复杂计算、网络请求等耗时操作,会直接卡住整个事件循环,阻塞所有其他事件的调度,造成全局卡顿。
完整解决方案:严格遵守回调极简原则,回调函数只做「数据接收、数据转发、状态标记、参数透传」等轻量操作。所有耗时业务、阻塞任务,全部抛给子线程/线程池异步处理,回调函数快速执行完毕并返回,不阻塞主线程事件循环,保证所有事件正常调度。
坑5:多线程共享全局 event_base,跨线程操作事件
详细现象:单线程运行程序完全正常,引入多线程后出现随机崩溃、段错误;偶尔事件重复触发、数据错乱、客户端连接异常断开;问题复现概率随机,难以调试定位,是新手多线程开发的隐形大坑。
深层原因:Libevent 核心设计中,event_base 事件基座是非线程安全的。event_base 内部维护着事件队列、就绪队列、状态标记等共享数据结构,且源码内部未做任何线程互斥锁保护。如果多个线程同时读写同一个 event_base、同时操作事件的注册、删除、触发,会造成内存数据错乱、队列破坏,最终引发随机段错误、程序崩溃。
完整解决方案:严格遵循 单线程单 base 原则,一个 event_base 只绑定一个线程,所有事件的创建、添加、删除、释放操作,全部在所属线程内完成。禁止跨线程调用 event_base、禁止多线程共享同一个事件对象。如需高并发多线程开发,采用「多 base 多线程」模型,每个线程独立维护专属事件基座,完全隔离。
第七部分:总结与新手学习路线
7.1 纯Event学习总结
本文全程基于原生 event 基础API,无任何复杂高级组件,完全适配新手入门:
1. 掌握 event_base 基座、事件循环、资源释放流程;
2. 熟练使用 event_new/evtimer_new/evsignal_new 创建各类事件;
3. 理解事件驱动、非阻塞 IO、Reactor 核心思想;
4. 可独立编写定时器、信号监听、并发TCP服务器。
7.2 新手进阶路线
学好本文纯Event基础后,可后续进阶:多线程模型、资源池封装、聊天室项目、bufferevent高级用法、SSL加密通信。
附录:编译运行常见问题
1. 编译报错 undefined reference:缺失 -levent 编译参数;
2. 端口绑定失败:端口被占用,更换端口或 kill 占用进程;
3. 事件不触发:优先检查非阻塞设置、EV_PERSIST宏、event_add调用三点。
尾语
本篇文章作为 Libevent 纯Event零基础入门教程,彻底摒弃了新手难以理解的 bufferevent 高级封装,回归 Libevent 最本源、最核心的原生事件机制,从环境安装、核心API解析,到实战案例、原理讲解、高频避坑,形成一套完整的新手学习闭环。
对于刚接触事件驱动、非阻塞IO编程的开发者而言,不必急于钻研复杂的高级特性。真正的网络高并发核心思想,全部藏在 event_base 事件循环、event 事件封装、回调驱动机制 中。吃透本文的基础知识点,就彻底理解了 epoll 多路复用、Reactor 模型的底层逻辑,为后续进阶复杂网络编程打下坚实的基础。
Libevent 的精髓不在于繁多的API,而在于「非阻塞、事件驱动、单线程高并发」的设计思想。熟练掌握定时器、信号监听、TCP并发服务器的基础写法,规避新手常见的编程坑点,你就已经具备了开发轻量高并发服务的基础能力。
后续只需在本文基础上,逐步拓展多线程协同、资源优化、协议解析等进阶内容,就能稳步从新手入门,成长为熟练掌握 Linux 高并发网络编程的开发者。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐
所有评论(0)