C# Dbus文件传输 C#在Linux上如何通过D-Bus服务交换文件

1次阅读

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

C# Dbus文件传输 C#在Linux上如何通过D-Bus服务交换文件

DBus 文件传输不是标准能力,得自己封装

D-Bus 协议本身不支持直接传文件,它只传序列化后的基本类型(Stringint32byte[] 等),且有默认消息大小限制(通常 128 MiB,但多数服务端会更早拒绝大消息)。想用 D-Bus 传文件,本质是把文件内容读成 byte[] 再塞进方法调用或信号里——这在小文件(

常见错误现象:org.freedesktop.DBus.Error.NoMemoryorg.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,容易死锁;用 awaitTask.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_UNIX socket(用 System.Net.Sockets.UnixDomainSocketEndPoint),支持流式、分块、取消
  • 或暴露一个本地 HTTP endpoint(如 http://127.0.0.1:34567/file?id=abc123),客户端用 HttpClient 下载
  • Flatpak/Snap 应用则倾向用 xdg-document-portal(通过 org.freedesktop.portal.Documents D-Bus 接口获取沙盒外文件句柄)

硬把大文件塞进 D-Bus 唯一的好处是“简单”,代价是调试困难、行为不一致、难以取消或断点续传——这些细节在开发后期才暴露,但改起来已牵一发而动全身。

text=ZqhQzanResources