Multipeer Connectivity、Bonjour和Network Framework 三种方式创建
一、使用 Multipeer Connectivity 实现点对点局域网
功能:设备间通过蓝牙或 Wi-Fi 直连,无需路由器,直接通信。
1. 初始化代码(Swift)
import MultipeerConnectivity
import UIKit
class PeerSessionManager: NSObject {
static let shared = PeerSessionManager()
private let serviceType = "my-local-network" // 自定义服务标识(必须小写)
private var peerID: MCPeerID!
private var session: MCSession!
private var advertiser: MCNearbyServiceAdvertiser!
private var browser: MCNearbyServiceBrowser!
// 初始化
override init() {
super.init()
setupPeerSession()
}
private func setupPeerSession() {
peerID = MCPeerID(displayName: UIDevice.current.name)
session = MCSession(peer: peerID, securityIdentity: nil, encryptionPreference: .required)
session.delegate = self
// 广播自身
advertiser = MCNearbyServiceAdvertiser(peer: peerID, discoveryInfo: nil, serviceType: serviceType)
advertiser.delegate = self
advertiser.startAdvertisingPeer()
// 搜索附近设备
browser = MCNearbyServiceBrowser(peer: peerID, serviceType: serviceType)
browser.delegate = self
browser.startBrowsingForPeers()
}
// 发送数据(例如发送字符串)
func sendMessage(_ message: String) {
guard let data = message.data(using: .utf8), !session.connectedPeers.isEmpty else { return }
do {
try session.send(data, toPeers: session.connectedPeers, with: .reliable)
} catch {
print("发送失败: \(error)")
}
}
}
// MARK: - MCSessionDelegate 处理会话状态和数据接收
extension PeerSessionManager: MCSessionDelegate {
func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
switch state {
case .connected:
print("已连接: \(peerID.displayName)")
case .connecting:
print("连接中...")
case .notConnected:
print("断开连接: \(peerID.displayName)")
@unknown default:
break
}
}
func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
if let message = String(data: data, encoding: .utf8) {
print("收到消息: \(message)")
// 在主线程更新 UI
DispatchQueue.main.async {
// 显示消息到界面
}
}
}
// 以下方法按需实现(文件/流传输)
func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {}
func session(_ session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, with progress: Progress) {}
func session(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL?, withError error: Error?) {}
}
// MARK: - Advertiser & Browser Delegates
extension PeerSessionManager: MCNearbyServiceAdvertiserDelegate, MCNearbyServiceBrowserDelegate {
// 收到连接请求
func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: Data?, invitationHandler: @escaping (Bool, MCSession?) -> Void) {
invitationHandler(true, session) // 自动接受邀请
}
// 发现附近设备
func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) {
browser.invitePeer(peerID, to: session, withContext: nil, timeout: 10) // 自动邀请对方
}
func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) {
print("设备离线: \(peerID.displayName)")
}
}
2. 在 Info.plist 中添加权限
<key>NSLocalNetworkUsageDescription</key>
<string>需要访问本地网络以发现附近设备</string>
<key>NSBonjourServices</key>
<array>
<string>_my-local-network._tcp</string> <!-- 格式:_服务类型._协议 -->
</array>
二、使用 Network Framework 创建 TCP 局域网
功能:在设备连接到同一 Wi-Fi 时,通过 TCP/IP 协议通信。
1. TCP 服务端代码(接收数据)
import Network
class TCPServer {
private var listener: NWListener?
func startServer() {
let parameters = NWParameters.tcp
listener = try? NWListener(using: parameters, on: 1234) // 端口号
listener?.stateUpdateHandler = { state in
switch state {
case .ready: print("服务器已启动")
case .failed(let error): print("服务器错误: \(error)")
default: break
}
}
listener?.newConnectionHandler = { connection in
self.handleConnection(connection)
}
listener?.start(queue: .main)
}
private func handleConnection(_ connection: NWConnection) {
connection.start(queue: .main)
connection.receive(minimumIncompleteLength: 1, maximumLength: 4096) { data, _, _, _ in
if let data = data, let message = String(data: data, encoding: .utf8) {
print("收到消息: \(message)")
}
connection.cancel() // 关闭连接(可选)
}
}
}
2. TCP 客户端代码(发送数据)
class TCPClient {
func sendMessage(_ message: String, host: String, port: UInt16) {
let connection = NWConnection(host: NWEndpoint.Host(host), port: NWEndpoint.Port(rawValue: port)!, using: .tcp)
connection.stateUpdateHandler = { state in
switch state {
case .ready:
let data = message.data(using: .utf8)!
connection.send(content: data, completion: .idempotent)
print("消息已发送")
case .failed(let error):
print("连接失败: \(error)")
default: break
}
}
connection.start(queue: .main)
}
}
三、关键步骤说明
- Multipeer Connectivity 适合无需互联网的离线场景(如游戏联机、文件传输)。
- Network Framework 适合需要精细控制网络协议的场景(如自定义 TCP/UDP)。
- 测试时确保设备:
- 开启蓝牙和 Wi-Fi(即使未连接路由器)。
- 关闭防火墙或 VPN。
- 在同一物理网络范围内。