内容纲要
基于 UNIX Domain Socket 的双向通信框架,核心原理模型如下:

Server[服务端] -->|监听| Socket[/tmp/dbus-name]
Client[客户端] -->|连接| Socket
Server --> Thread1[监听线程]
Client --> Thread2[方法线程]
服务端:创建监听套接字(socket+bind+listen),接受其他进程的连接
客户端:主动连接服务端(socket+connect),建立双向通道
多线程:使用独立线程处理连接监听(listenThread)和方法调用(methodThread)
1. 该函数实现基于 UNIX Domain Socket 的双向通信框架,主要完成:
- 服务端:创建监听套接字、绑定地址、启动监听线程
- 客户端:创建连接套接字、尝试重连、启动方法调用线程
- 线程安全:通过互斥锁 (
dbus_mutex) 保护共享资源
- UNIX Domain Socket特点
高效性:内核直接传递数据,无需网络协议栈
可靠性:面向连接(SOCK_STREAM),保证数据顺序
安全性:通过文件系统权限控制访问(/tmp/dbus-*)

2.程序实现
#include <sys/un.h>
#include <fcntl.h>
#include <poll.h>
#define UNIX_PATH_MAX 108
#define MAX_RETRY_ATTEMPTS 100 // 50ms * 100 = 5s
#define DETACHED_THREAD 1
/* 服务端初始化 */
static int init_server(ZRTDbusInfo dbusInfo) {
struct sockaddr_un srv_addr;
pthread_attr_t thread_attr;
// 创建UNIX域套接字
dbusInfo->socket_server = socket(AF_UNIX, SOCK_STREAM, 0);
if (dbusInfo->socket_server < 0) {
perror("socket() server failed");
return -1;
}
// 生成安全的套接字路径
if (snprintf(dbusInfo->unix_domain, UNIX_PATH_MAX,
"/tmp/dbus-%.32s", dbusInfo->name) >= UNIX_PATH_MAX) {
fprintf(stderr, "Unix domain path too long\n");
close(dbusInfo->socket_server);
return -1;
}
// 清理旧套接字文件
unlink(dbusInfo->unix_domain);
// 配置地址结构
memset(&srv_addr, 0, sizeof(srv_addr));
srv_addr.sun_family = AF_UNIX;
strncpy(srv_addr.sun_path, dbusInfo->unix_domain, sizeof(srv_addr.sun_path)-1);
srv_addr.sun_path[sizeof(srv_addr.sun_path)-1] = '\0';
// 绑定地址
if (bind(dbusInfo->socket_server, (struct sockaddr*)&srv_addr,
sizeof(srv_addr)) < 0) {
perror("bind() failed");
close(dbusInfo->socket_server);
return -1;
}
// 设置监听队列
if (listen(dbusInfo->socket_server, MAX_LISTEN_NUM) < 0) {
perror("listen() failed");
close(dbusInfo->socket_server);
unlink(dbusInfo->unix_domain);
return -1;
}
// 创建分离线程
pthread_attr_init(&thread_attr);
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
if (pthread_create(&dbusInfo->listenThread_t, &thread_attr,
ZRT_Dbus_Listen_Thread, dbusInfo) != 0) {
pthread_attr_destroy(&thread_attr);
close(dbusInfo->socket_server);
unlink(dbusInfo->unix_domain);
return -1;
}
pthread_attr_destroy(&thread_attr);
return 0;
}
/* 客户端初始化(带非阻塞连接) */
static int init_client(ZRTDbusInfo dbusInfo) {
struct sockaddr_un srv_addr;
char server_path[UNIX_PATH_MAX];
pthread_attr_t thread_attr;
int flags, ret;
// 创建客户端套接字
if ((dbusInfo->socket_client = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("socket() client failed");
return -1;
}
// 生成服务端路径
snprintf(server_path, UNIX_PATH_MAX, "/tmp/dbus-%.32s", dbusInfo->dst_name);
// 配置地址结构
memset(&srv_addr, 0, sizeof(srv_addr));
srv_addr.sun_family = AF_UNIX;
strncpy(srv_addr.sun_path, server_path, sizeof(srv_addr.sun_path)-1);
srv_addr.sun_path[sizeof(srv_addr.sun_path)-1] = '\0';
// 设置为非阻塞模式
flags = fcntl(dbusInfo->socket_client, F_GETFL, 0);
fcntl(dbusInfo->socket_client, F_SETFL, flags | O_NONBLOCK);
// 带超时的连接
int connected = 0;
struct pollfd pfd = { .fd = dbusInfo->socket_client, .events = POLLOUT };
for (int i = 0; i < MAX_RETRY_ATTEMPTS; ++i) {
ret = connect(dbusInfo->socket_client, (struct sockaddr*)&srv_addr,
sizeof(srv_addr));
if (ret == 0) {
connected = 1;
break;
}
if (errno == EINPROGRESS) {
// 使用poll等待连接完成
if (poll(&pfd, 1, 50) > 0 && (pfd.revents & POLLOUT)) {
socklen_t len = sizeof(ret);
getsockopt(dbusInfo->socket_client, SOL_SOCKET, SO_ERROR, &ret, &len);
if (ret == 0) {
connected = 1;
break;
}
}
}
usleep(50000); // 50ms
}
if (!connected) {
fprintf(stderr, "Connection timeout to %s\n", dbusInfo->dst_name);
close(dbusInfo->socket_client);
dbusInfo->socket_client = -1;
return -1;
}
// 恢复阻塞模式
fcntl(dbusInfo->socket_client, F_SETFL, flags);
// 创建方法线程
pthread_attr_init(&thread_attr);
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
if (pthread_create(&dbusInfo->methodThread_t, &thread_attr,
ZRT_Dbus_Method_Thread, dbusInfo) != 0) {
pthread_attr_destroy(&thread_attr);
close(dbusInfo->socket_client);
dbusInfo->socket_client = -1;
return -1;
}
pthread_attr_destroy(&thread_attr);
return 0;
}
/* 主注册函数 */
int ZRT_Dbus_Register(ZRTDbusInfo *dbusInfo) {
// 参数校验
if (!dbusInfo || !dbusInfo->name[0]) {
fprintf(stderr, "Invalid parameters\n");
return -1;
}
// 初始化互斥锁
if (pthread_mutex_init(&dbusInfo->dbus_mutex, NULL) != 0) {
perror("pthread_mutex_init failed");
return -1;
}
// 服务端初始化
if (dbusInfo->interface_num > 0) {
if (init_server(dbusInfo) < 0) {
goto cleanup_mutex;
}
}
// 客户端初始化
if (dbusInfo->dst_name[0]) {
if (init_client(dbusInfo) < 0) {
goto cleanup_server;
}
}
return 0;
cleanup_server:
if (dbusInfo->socket_server >= 0) {
close(dbusInfo->socket_server);
unlink(dbusInfo->unix_domain);
}
cleanup_mutex:
pthread_mutex_destroy(&dbusInfo->dbus_mutex);
return -1;
}
3。 dbus 通信优势
| 目标 | 实现方式 | 优势 |
|---|---|---|
| 双向通信 | 同时支持服务端和客户端模式 | 可同时处理请求和主动发起调用 |
| 资源安全 | 互斥锁保护 + 错误路径资源释放 | 避免内存/文件描述符泄漏 |
| 连接可靠性 | 客户端带超时重连机制 | 容忍服务端暂时不可用 |
| 高并发处理 | 分离监听线程和方法线程 | 避免主线程阻塞 |
版权声明
内容来源及使用限制
欢迎访问 TomgZHE研习社(网址:https://blog.tomgzhe.com)。本网站部分文章内容源自网络,仅作学习交流与参考分享;若您发现有内容涉嫌侵权,请立即联系 tomgzhe@qq.com,我们将在接到通知后的 48 小时内核实并删除相关侵权内容。
软件资源相关规定
本网站为个人非盈利性质的站点,所有软件资源均来自网络。这些资源仅用于个人学习、研究和参考,严禁用于任何商业用途。您下载和使用本网站软件资源即表示您同意仅将其用于学习目的,若因违反此规定导致任何法律纠纷或损失,责任由您自行承担。
原创版权
本网站上的原创内容,包括但不限于文字作品、自行设计的图片、独家制作的音频视频等,其版权均归本网站所有。未经本网站书面授权,任何组织或个人不得擅自复制、转载、摘编、传播或以其他任何方式使用这些原创内容。如需使用,请提前与我们联系并获得书面许可,同时需在显著位置注明出处及作者信息。
转载与引用规范
若您需转载本网站文章,务必注明文章来源为 “[],原文链接:[]”;对于有明确作者署名的文章,还需完整保留作者姓名。在引用本网站内容时,请确保内容准确无误,并遵循学术及行业的引用规范。
微信扫一扫打赏
支付宝扫一扫打赏
Comments(1)
[…] 系统以顶层的APP应用模块为入口,通过Dbus-A和network Dbus(Dbus-B)双接口与中间件通信:Dbus-A负责接收上层应用的广播、信号与方法调用,Dbus-B则专用于网络方法请求。核心中间层由lib SDK实现业务逻辑整合,其向下提供网络服务API(如OTA更新、netlink通信、设备上电控制等),并基于共享内存机制将数据流拆分为双独立通道——左侧通道通过“channel ctrl”模块管理SDIO接口的WiFi驱动,实现网络数据流传输;右侧通道通过“media ctrl”模块控制MIPI-CSI接口的摄像头驱动,处理图像媒体流。 两通道在共享内存层实现硬件访问隔离,最终由底层驱动直接操作SDIO与MIPI-CSI硬件协议完成数据交互。整个架构通过Dbus接口解耦应用与硬件逻辑,利用并行通道设计兼顾网络与媒体数据的高效处理,形成层次分明、扩展灵活的系统解决方案。 对DBUG不熟悉,可看文章DBUS交互实现。 […]