You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Swift中使用UNIX domain sockets实现IPC进程间通信

基于UNIX Domain Socket的Swift IPC实现教程

核心逻辑

UNIX Domain Socket是专门用于本地进程间通信的socket实现,不需要走网络栈,性能更高,核心流程非常简单:

  • 服务端流程:创建socket → 绑定到本地文件路径 → 监听连接请求 → 接收客户端连接 → 读写数据
  • 客户端流程:创建socket → 连接到服务端绑定的文件路径 → 读写数据
  • 注意:UNIX Domain Socket绑定的文件路径最大长度限制为104字节,尽量放在/tmp这类短路径目录下,服务端启动前必须删除上次运行残留的socket文件,否则绑定会报错。

Swift实现不需要引入任何第三方库,直接调用系统内置的BSD Socket接口即可,import Darwin后就能用所有相关接口。

最简可运行实现

服务端代码

import Darwin

// 自定义socket存储路径,不要超过104字节
let socketPath = "/tmp/my_swift_ipc_socket"

// 先删除旧的socket文件,避免绑定失败
unlink(socketPath)

// 创建socket:AF_UNIX代表本地域,SOCK_STREAM代表可靠流传输
let serverFD = socket(AF_UNIX, SOCK_STREAM, 0)
guard serverFD != -1 else {
    fatalError("创建socket失败")
}

// 配置socket地址信息
var addr = sockaddr_un()
addr.sun_len = UInt8(MemoryLayout<sockaddr_un>.size) // MacOS必填字段
addr.sun_family = sa_family_t(AF_UNIX)
_ = withUnsafeMutableBytes(of: &addr.sun_path) { pathPtr in
    socketPath.withCString { cStr in
        strcpy(pathPtr.baseAddress?.assumingMemoryBound(to: CChar.self), cStr)
    }
}
let addrLen = socklen_t(MemoryLayout<sockaddr_un>.size)

// 绑定socket到指定路径
let bindResult = withUnsafePointer(to: &addr) { addrPtr in
    addrPtr.withMemoryRebound(to: sockaddr.self, capacity: 1) { sockAddrPtr in
        bind(serverFD, sockAddrPtr, addrLen)
    }
}
guard bindResult != -1 else {
    fatalError("绑定socket失败,请检查路径权限")
}

// 启动监听,最大支持5个待处理连接
let listenResult = listen(serverFD, 5)
guard listenResult != -1 else {
    fatalError("启动监听失败")
}
print("服务端启动成功,等待客户端连接...")

// 阻塞等待客户端连接
let clientFD = accept(serverFD, nil, nil)
guard clientFD != -1 else {
    fatalError("接收客户端连接失败")
}
print("客户端已接入")

// 读取客户端发送的消息
var buffer = [CChar](repeating: 0, count: 1024)
let readLength = read(clientFD, &buffer, 1024)
if readLength > 0 {
    let receivedMsg = String(cString: buffer)
    print("收到客户端消息:\(receivedMsg)")
    
    // 给客户端返回响应
    let response = "服务端已收到消息:\(receivedMsg)"
    response.withCString { cStr in
        write(clientFD, cStr, strlen(cStr))
    }
}

// 关闭连接,清理socket文件
close(clientFD)
close(serverFD)
unlink(socketPath)

客户端代码

import Darwin

let socketPath = "/tmp/my_swift_ipc_socket"

// 创建socket
let clientFD = socket(AF_UNIX, SOCK_STREAM, 0)
guard clientFD != -1 else {
    fatalError("创建socket失败")
}

// 配置服务端地址
var addr = sockaddr_un()
addr.sun_len = UInt8(MemoryLayout<sockaddr_un>.size)
addr.sun_family = sa_family_t(AF_UNIX)
_ = withUnsafeMutableBytes(of: &addr.sun_path) { pathPtr in
    socketPath.withCString { cStr in
        strcpy(pathPtr.baseAddress?.assumingMemoryBound(to: CChar.self), cStr)
    }
}
let addrLen = socklen_t(MemoryLayout<sockaddr_un>.size)

// 连接服务端
let connectResult = withUnsafePointer(to: &addr) { addrPtr in
    addrPtr.withMemoryRebound(to: sockaddr.self, capacity: 1) { sockAddrPtr in
        connect(clientFD, sockAddrPtr, addrLen)
    }
}
guard connectResult != -1 else {
    fatalError("连接服务端失败,请确认服务端已启动且路径正确")
}

// 发送消息
let sendMsg = "Hello IPC from Swift Client"
sendMsg.withCString { cStr in
    write(clientFD, cStr, strlen(cStr))
}
print("消息已发送")

// 接收服务端返回
var buffer = [CChar](repeating: 0, count: 1024)
let readLength = read(clientFD, &buffer, 1024)
if readLength > 0 {
    let response = String(cString: buffer)
    print("收到服务端响应:\(response)")
}

// 关闭连接
close(clientFD)

运行方法

  1. 把服务端代码存为Server.swift,执行swiftc Server.swift -o ipc_server编译,运行./ipc_server启动服务端
  2. 把客户端代码存为Client.swift,执行swiftc Client.swift -o ipc_client编译,新开终端运行./ipc_client即可看到通信效果

进阶优化方向

你可以在跑通基础版本后逐步扩展功能:

  • 用GCD的DispatchSource监听文件描述符的可读/可写事件,把同步阻塞逻辑改成异步,避免卡住主线程
  • 封装成独立的工具类,自动处理异常断开、自动重连、数据粘包拆分问题
  • 需要传输复杂结构体时,可以把数据序列化成JSON、Protobuf格式后再发送

内容的提问来源于stack exchange,提问作者Tyler Smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 14:27:02