iOS 创建局域网

272 阅读2分钟

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)
    }
}

三、关键步骤说明

  1. Multipeer Connectivity 适合无需互联网的离线场景(如游戏联机、文件传输)。
  2. Network Framework 适合需要精细控制网络协议的场景(如自定义 TCP/UDP)。
  3. 测试时确保设备:
  • 开启蓝牙和 Wi-Fi(即使未连接路由器)。
  • 关闭防火墙或 VPN。
  • 在同一物理网络范围内。