Swift基于TCP实现聊天APP的疑问及代码报错咨询
TCP双向字符串传输疑问解答及代码修复
疑问解答
- 两台不同Mac设备的模拟器是否可实现?
可以。前提是两台Mac处于同一局域网,模拟器能够访问对方Mac的IP地址,同时两台Mac的防火墙都允许8080端口的TCP连接请求。 - 同一Mac设备的两个模拟器是否可实现?
完全可以。可以使用Mac的本地回环地址127.0.0.1或者局域网IP,将两个模拟器分别配置为TCP客户端和服务端即可。 - 替换Mac的IP并使用8080端口是否可行?
可行,但需要确认两点:一是8080端口未被其他程序占用;二是Mac的防火墙允许该端口的TCP入站/出站流量。
报错原因分析
你遇到的nw_socket_handle_socket_event [C1:1] Socket SO_ERROR [61: Connection refused]错误,本质是TCP连接请求被拒绝,核心原因是:你的代码只实现了TCP客户端,但没有对应的TCP服务端在目标IP的8080端口上监听连接请求。
代码修复与补充
1. 补充TCP服务端实现
首先需要实现一个TCP服务端来监听8080端口,接收客户端连接并处理双向通信:
class NWTCPServer: NSObject { var listener: NWListener! func startServer() { let port = NWEndpoint.Port(rawValue: 8080)! let queue = DispatchQueue(label: "TCP Server Queue") let tcpOptions = NWProtocolTCP.Options() tcpOptions.noDelay = true let params = NWParameters(tls: nil, tcp: tcpOptions) do { listener = try NWListener(using: params, on: port) } catch { print("Failed to create listener: \(error)") return } listener.stateUpdateHandler = { newState in switch newState { case .ready: print("Server is ready to accept connections") case .failed(let error): print("Server failed: \(error)") default: break } } listener.newConnectionHandler = { connection in print("New client connected") self.handleConnection(connection: connection) } listener.start(queue: queue) } private func handleConnection(connection: NWConnection) { let queue = DispatchQueue(label: "Connection Queue") connection.start(queue: queue) connection.stateUpdateHandler = { newState in switch newState { case .ready: print("Client connection ready") self.receiveFromConnection(connection: connection) // 示例:给客户端发送响应 self.sendToConnection(connection: connection, message: "Hello from server!") case .failed(let error): print("Client connection failed: \(error)") connection.cancel() case .cancelled: print("Client connection cancelled") default: break } } } private func sendToConnection(connection: NWConnection, message: String) { guard let data = message.data(using: .utf8) else { return } connection.send(content: data, completion: .contentProcessed { error in if let error = error { print("Server send error: \(error)") } else { print("Server sent message: \(message)") } }) } private func receiveFromConnection(connection: NWConnection) { connection.receiveMessage { data, context, isComplete, error in if let error = error { print("Server receive error: \(error)") return } if let data = data, isComplete { if let message = String(data: data, encoding: .utf8) { print("Server received message: \(message)") } // 循环接收下一条消息 self.receiveFromConnection(connection: connection) } } } }
2. 修复客户端代码的问题
你的客户端代码存在两个主要问题:一是receive方法只接收一次消息,二是未处理连接失败的具体状态。以下是修复后的客户端代码:
class NWTCPConnection: NSObject { var connection: NWConnection! func connectToTcp() { let PORT: NWEndpoint.Port = 8080 // 同一Mac模拟器用127.0.0.1,不同Mac用对方的局域网IP let ipAddress: NWEndpoint.Host = "127.0.0.1" let queue = DispatchQueue(label: "TCP Client Queue") let tcp = NWProtocolTCP.Options() tcp.noDelay = true let params = NWParameters(tls: nil, tcp: tcp) connection = NWConnection(to: NWEndpoint.hostPort(host: ipAddress, port: PORT), using: params) connection.stateUpdateHandler = { [weak self] newState in guard let self = self else { return } switch newState { case .ready: print("Socket State: Ready") UserDefaults.standard.set(true, forKey: "isConnected") self.sendMSG() self.receive() case .failed(let error): print("Socket connection failed: \(error)") UserDefaults.standard.set(false, forKey: "isConnected") self.connection.cancel() case .cancelled: print("Socket connection cancelled") UserDefaults.standard.set(false, forKey: "isConnected") default: UserDefaults.standard.set(false, forKey: "isConnected") break } } connection.start(queue: queue) } func sendMSG() { print("send data") let message1 = "hello world" guard let content = message1.data(using: .utf8) else { return } connection.send(content: content, completion: NWConnection.SendCompletion.contentProcessed({ error in if let error = error { print("ERROR! Error when sending data: \(error)") } else { print("Data was sent to TCP destination ") } })) } // 循环接收消息,确保能持续接收服务端发送的内容 func receive() { connection.receiveMessage { [weak self] data, context, isComplete, error in guard let self = self else { return } if let error = error { print("Client receive error: \(error)") return } if isComplete, let data = data { print("Receive is complete, count bytes: \(data.count)") if let message = String(data: data, encoding: .utf8) { print("Client received message: \(message)") } else { print("Data is not valid UTF-8 string") } // 继续接收下一条消息 self.receive() } } } }
3. 使用方式
- 在其中一个模拟器中启动服务端:
let server = NWTCPServer() server.startServer() - 在另一个模拟器(或另一台Mac的模拟器)中启动客户端:
let client = NWTCPConnection() client.connectToTcp()
额外注意事项
- 确认端口占用:可以在Mac终端用
lsof -i :8080命令检查8080端口是否被占用,若被占用需更换端口或关闭占用程序。 - 防火墙设置:进入Mac系统偏好设置→安全与隐私→防火墙,确保允许你的应用程序接收传入连接。
内容的提问来源于stack exchange,提问作者danu
相关产品推荐
相关产品推荐

