Linux下使用C++17获取指定USB端口连接设备的产品名称
Linux下C++17获取指定端口对应USB设备产品名实现方案
Linux内核会将所有USB设备的元信息暴露在sysfs虚拟文件系统中,无需解析dmesg输出、无需依赖第三方库,直接读取对应文件即可拿到设备产品名,稳定性远高于日志解析方案,且普通用户权限即可操作。
核心原理
所有挂载到用户空间的设备端口,在/sys/class/目录下都有对应条目:
- ACM串口设备对应路径规则:
/sys/class/tty/ttyACM<端口号>/device - HIDRaw设备对应路径规则:
/sys/class/hidraw/hidraw<端口号>/device
上述路径是指向USB设备接口目录的软链接,逐级向上遍历父目录,直到找到同时包含idVendor、product属性文件的目录,即为USB设备的根目录。其中product文件存储的纯文本内容,就是dmesg日志中显示的产品名称字段,同目录下还可读取manufacturer(厂商名)、serial(设备序列号)、idProduct(产品ID)等属性。
C++17 实现代码
使用C++17标准库的filesystem模块处理路径与软链接,无需额外依赖:
#include <filesystem> #include <fstream> #include <string> #include <optional> #include <algorithm> #include <cctype> namespace fs = std::filesystem; std::optional<std::string> get_usb_product_name(const std::string& dev_path) { // 从/dev/xxx路径提取设备文件名 std::string dev_name = fs::path(dev_path).filename().string(); fs::path sys_dev_path; // 匹配不同设备类型的sysfs起始路径 if (dev_name.size() >= 6 && dev_name.substr(0, 6) == "ttyACM") { sys_dev_path = fs::path("/sys/class/tty") / dev_name / "device"; } else if (dev_name.size() >= 6 && dev_name.substr(0, 6) == "hidraw") { sys_dev_path = fs::path("/sys/class/hidraw") / dev_name / "device"; } else { return std::nullopt; // 非支持的设备类型 } if (!fs::exists(sys_dev_path)) { return std::nullopt; // 设备不存在 } // 逐级向上查找USB设备根目录(包含product和idVendor文件的目录) fs::path current_path = fs::canonical(sys_dev_path); while (current_path != current_path.root_path()) { if (fs::exists(current_path / "idVendor") && fs::exists(current_path / "product")) { // 读取product文件内容 std::ifstream product_file(current_path / "product"); if (!product_file.is_open()) { return std::nullopt; } std::string product_name; std::getline(product_file, product_name); // 去除末尾可能的空白字符 product_name.erase(std::find_if(product_name.rbegin(), product_name.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), product_name.end()); return product_name; } current_path = current_path.parent_path(); } return std::nullopt; } // 调用示例 int main() { auto acm0_product = get_usb_product_name("/dev/ttyACM0"); if (acm0_product.has_value()) { printf("ttyACM0 对应设备产品名: %s\n", acm0_product->c_str()); } auto hidraw8_product = get_usb_product_name("/dev/hidraw8"); if (hidraw8_product.has_value()) { printf("hidraw8 对应设备产品名: %s\n", hidraw8_product->c_str()); // 示例场景下会输出: hidraw8 对应设备产品名: Teensyduino RawHID } return 0; }
编译时需要开启C++17标准,GCC 9以下版本需额外链接filesystem库,编译命令参考:g++ -std=c++17 usb_check.cpp -o usb_check -lstdc++fs
优化建议
- 如果接入的是多台同型号设备,仅靠产品名无法区分,可读取同目录下的
serial文件获取设备唯一序列号做永久绑定匹配,可靠性更高 - 该方案默认支持ttyACM、hidraw两类设备,如果需要支持ttyUSB等其他USB转串口设备,只需要在路径匹配部分增加对应规则即可
- 不推荐解析dmesg输出实现该功能:dmesg读取通常需要root权限,且系统日志轮转、历史日志残留都会导致解析结果错误
内容的提问来源于stack exchange,提问作者Marenator
相关产品推荐
相关产品推荐

