dbus不支持直接传文件,仅能传输序列化基本类型;小文件可转byte[]或base64传,但推荐dbus只传元数据,文件走临时目录、unix socket或http等专用通道。

DBus 文件传输不是标准能力,得自己封装
D-Bus 协议本身不支持直接传文件,它只传序列化后的基本类型(string、int32、byte[] 等),且有默认消息大小限制(通常 128 MiB,但多数服务端会更早拒绝大消息)。想用 D-Bus 传文件,本质是把文件内容读成 byte[] 再塞进方法调用或信号里——这在小文件(
常见错误现象:org.freedesktop.DBus.Error.NoMemory、org.freedesktop.DBus.Error.Failed(带 “Message too large”)、方法调用无响应或超时(TimeoutException)。
- 别用
byte[]直传 >512 KiB 的文件;实际建议上限设为 64 KiB - 若必须传中等文件(如配置包、图标),先用
Convert.ToBase64String()编码再传字符串,接收方反解——但 Base64 体积膨胀 ~33%,且增加 CPU 开销 - 真实场景推荐:D-Bus 只传元数据(路径、校验和、大小),文件走本地临时目录 + 文件系统共享,或走 HTTP/Unix socket 等专用通道
用 Tmds.DBus 在 C# 中发送小文件字节流
Tmds.DBus 是目前 Linux 上最稳定的 .NET D-Bus 客户端库(支持 net6+),它允许你把 byte[] 当作 bytearray 类型传入 D-Bus 方法。关键点在于接口定义必须显式声明参数为 ay(D-Bus 的 byte array 类型)。
服务端接口示例(XML):
<method name="SendFile"> <arg type="s" name="filename" direction="in"/> <arg type="ay" name="data" direction="in"/> </method>
客户端调用片段:
var connection = new Connection(Address.System);
await connection.ConnectAsync();
var proxy = connection.CreateProxy("com.example.FileService",
"/com/example/FileService",
"com.example.FileService");
byte[] fileBytes = await File.ReadAllBytesAsync("/tmp/test.txt");
await proxy.CallAsync("SendFile", "test.txt", fileBytes); // 第三个参数自动映射为 ay- 确保服务端实现对
ay参数做了长度检查,避免 OOM - 调用前设置超时:
proxy.Timeout = TimeSpan.FromSeconds(30),否则默认可能只有 25 秒 - 不要在 UI 线程同步等待
CallAsync,容易死锁;用await或Task.Run包裹
接收方如何安全还原文件并防冲突
服务端收到 byte[] 后不能直接写死路径。Linux 下多用户或沙盒环境(如 Flatpak)可能导致权限失败或路径不可写。
- 用
Path.GetTempFileName()创建唯一临时文件,再File.WriteAllBytes(),避免竞态和覆盖 - 传入的
filename仅作参考名,最终保存路径应由服务端策略决定(例如拼到/var/lib/myservice/uploads/或用户$XDG_CACHE_HOME) - 务必验证
data.Length是否与预期一致(比如从另一参数或 header 里拿到 size),防止截断或伪造 - 若需原子写入,先写临时文件,再
File.Move()覆盖目标——但注意跨文件系统时Move实为复制+删除
替代方案比硬扛 D-Bus 更可靠
真正做文件交换时,95% 的成熟服务(如 PulseAudio、GNOME Settings Daemon)都避开 D-Bus 传正文。它们用的是组合策略:
- D-Bus 传「通知」:例如
FileReceived(string id, string mime, long size, string sha256) - 文件本体走
AF_UNIXsocket(用System.Net.Sockets.UnixDomainSocketEndPoint),支持流式、分块、取消 - 或暴露一个本地 HTTP endpoint(如
http://127.0.0.1:34567/file?id=abc123),客户端用HttpClient下载 - Flatpak/Snap 应用则倾向用
xdg-document-portal(通过org.freedesktop.portal.DocumentsD-Bus 接口获取沙盒外文件句柄)
硬把大文件塞进 D-Bus 唯一的好处是“简单”,代价是调试困难、行为不一致、难以取消或断点续传——这些细节在开发后期才暴露,但改起来已牵一发而动全身。










