Post

Replies

Boosts

Views

Activity

UDP Receive is not working
Hello everyone I'm new to swift and I can't quite figure it out yet:( I am developing a simple online game for mac os that involves two players connected to the same WIFI. I need to constantly receive information from the server and I don't understand how to implement it. If I call the receive function indefinitely, then my program freezes. I realized that this should happen asynchronously, but that's just how my program understands when a package came from the server. I understand that I need a delegate or handler, but I don't understand how to do it. Please help me to add the receive function and everything that is necessary for it import Foundation import Network enum CustomErrors: Error { case DataError case NetworkError case DecoderError case InvalidAddress } class TapperConnection: ObservableObject { private var _serverAlive = false private var connection: NWConnection! private var serverPort: UInt16 = 20001 private var serverIp: String = "127.0.0.1" private var _myDeviceName = Host.current().localizedName ?? "" @Published var messageDc: [HostData] = [] @Published var messageLobby: [HostData] = [] @Published var messageState: GameData = GameData() private var buffer = 2048 private var _inputData = "" private var _outputData = "" private var _myIp = "" private var isServer = false private var isClient = false var myIp: String { return _myIp } var myDeviceName: String { return _myDeviceName } private func getMyIp() -> String? { var address: String? var ifaddr: UnsafeMutablePointer<ifaddrs>? guard getifaddrs(&ifaddr) == 0 else { return nil } guard let firstAddr = ifaddr else { return nil } for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) { let interface = ifptr.pointee let addrFamily = interface.ifa_addr.pointee.sa_family if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) { let name = String(cString: interface.ifa_name) if name == "en0" || name == "en2" || name == "en3" || name == "en4" || name == "pdp_ip0" || name == "pdp_ip1" || name == "pdp_ip2" || name == "pdp_ip3" { var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST)) getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.pointee.sa_len), &hostname, socklen_t(hostname.count), nil, socklen_t(0), NI_NUMERICHOST) address = String(cString: hostname) } } } freeifaddrs(ifaddr) return address } private func isValidIP(_ ip: String) -> Bool { let regex = try! NSRegularExpression(pattern: "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$") return regex.firstMatch(in: ip, range: NSRange(location: 0, length: ip.utf16.count)) != nil } @Sendable private func updateServerState(to state: NWConnection.State) { switch state { case .setup: _serverAlive = true case .waiting: _serverAlive = true case .ready: _serverAlive = true case .failed: _serverAlive = false case .cancelled: _serverAlive = false case .preparing: _serverAlive = false default: _serverAlive = false } } func createConnection() throws { let ip = getMyIp() if ip != nil { serverIp = ip! _myIp = ip! } else { throw CustomErrors.NetworkError } isServer = true do { try connectToServer() } catch { throw CustomErrors.NetworkError } } func createConnection(ip: String) throws { if isValidIP(ip) { serverIp = ip } else { throw CustomErrors.InvalidAddress } let _ip = getMyIp() if _ip != nil { _myIp = _ip! } else { throw CustomErrors.NetworkError } isClient = true do { try connectToServer() } catch { throw CustomErrors.NetworkError } } private func connectToServer() throws { if isServer { // ............... // run server exec // ............... } let _params = NWParameters(dtls: nil, udp: .init()) _params.requiredLocalEndpoint = NWEndpoint.hostPort(host: NWEndpoint.Host(_myIp), port: 20002) connection = NWConnection(host: NWEndpoint.Host(serverIp), port: NWEndpoint.Port(rawValue: serverPort)!, using: _params) connection.stateUpdateHandler = updateServerState(to:) connection.start(queue: .global()) while !_serverAlive {} do { try send(message: "im:\(_myDeviceName)") receive() } catch { print("Error sending disconnect message: \(error)") } } func closeConnection() { do { try send(message: "dc:\(_myDeviceName)") } catch { print("Error sending disconnect message: \(error)") } _serverAlive = false connection.cancel() } func send(message: String) throws { var error = false connection.send(content: message.data(using: String.Encoding.utf8), completion: NWConnection.SendCompletion.contentProcessed(({ NWError in if NWError == nil { print("Data was sent!") } else { error = true } }))) if error { throw CustomErrors.NetworkError } } func receive() { self.connection.receive(minimumIncompleteLength: 1, maximumLength: 65535) { data, _, isComplete, _ in if isComplete { if data != nil { let response: String = String(decoding: data!, as: UTF8.self) var decodeData: Any var messageType: MessageType (decodeData, messageType) = try! Decoder.decodeMessage(response) switch messageType { case MessageType.lobby: self.messageLobby = decodeData as! [HostData] case MessageType.state: self.messageState = decodeData as! GameData case MessageType.dc: self.messageDc = decodeData as! [HostData] } } self.receive() } } } }
1
0
173
Oct ’24