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

来源:这里教程网 时间:2026-02-21 17:43:15 作者:

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_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 唯一的好处是“简单”,代价是调试困难、行为不一致、难以取消或断点续传——这些细节在开发后期才暴露,但改起来已牵一发而动全身。

相关推荐

热文推荐