Network.framework nw_read_request_get_maximum_datagram_count

I'm trying to get a UDP server functioning within Network.framework. However, whenever I managed to get my client and server connected, after some time I receive the error

nw_read_request_get_maximum_datagram_count

I've tried looping with Timer and with DispatchQueue, but eventually the server or client crashes with the above error.


Client

import Foundation
import Network

class ExampleClient {
    lazy var connection: NWConnection = {
        let connection = NWConnection(
            to: .service(
                name: "Emma’s MacBook Pro",
                type: "_test._udp",
                domain: "local",
                interface: nil
            ),
            using: .udp
        )
        
        connection.stateUpdateHandler = { (newState) in
            switch newState {
            case .ready:
                self.loopForever()
            case .failed(let error):
                print("client failed with error: \(error)")
            default:
                break
            }
        }
        
        return connection
        
    }()
    
    func run() {
        connection.start(queue: DispatchQueue(label: "client"))
        
    }
    
    func loopForever() {
        while true {
            connection.send(content: "hello".data(using: .utf8), completion: .contentProcessed({ (error) in
                if let error = error {
                    print("error while sending hello: \(error)")
                }
                
                self.connection.receiveMessage { (data, context, isComplete, error) in
                    return
                    
                }
                
            }))
            
        }
        
    }
    
}

let client = ExampleClient()
client.run()

RunLoop.main.run()


Server

import Foundation
import Network

class ExampleServer {
    var connections = [NWConnection]()
    lazy var listener: NWListener = {
        let listener = try! NWListener(using: .udp)
        
        listener.service = NWListener.Service(type: "_test._udp")
        listener.serviceRegistrationUpdateHandler = { (serviceChange) in
            switch serviceChange {
            case .add(let endpoint):
                switch endpoint {
                case let .service(name, _, _, _):
                    print("listening as name \(name)")
                default:
                    break
                }
            default:
                break
            }
            
        }
        listener.newConnectionHandler = { (newConnection) in
            newConnection.start(queue: DispatchQueue(label: "new client"))
            self.connections.append(newConnection)
            
        }
        
        return listener
    
    }()

    func run() {
        self.listener.start(queue: DispatchQueue(label: "server"))
        
        while true {
            for connection in self.connections {
                connection.receiveMessage { (message, context, isComplete, error) in
                    connection.send(content: "world".data(using: .utf8), completion: .contentProcessed({ (error) in
                        if let error = error {
                            print("error while sending data: \(error)")
                            
                        }
                        
                    }))
                    
                }
                
            }
            
        }
        
    }
    
}

let server = ExampleServer()
server.run()

RunLoop.main.run()

I'd like to maintain a constant connection between the server and client until the client or server manually disconnect.

Answered by OOPer in 346897022

But generally, infinite loop is something you should better avoid. Especially in your case, `loopForever() in your client will send too many UDP packets to be processed by the server in a short period.


Client:

import Foundation
import Network

let ServerName = "OOPer's mini"

class ExampleClient {
    lazy var connection: NWConnection = {
        let connection = NWConnection(
            to: .service(
                name: ServerName,
                type: "_test._udp",
                domain: "local",
                interface: nil
            ),
            using: .udp
        )
        
        connection.stateUpdateHandler = {newState in
            switch newState {
            case .ready:
                print("connection ready")
                self.sendMessage()
            case .failed(let error):
                print("client failed with error: \(error)")
            default:
                break
            }
        }
        
        return connection
    }()
    
    func run() {
        connection.start(queue: DispatchQueue(label: "client"))
    }
    
    func sendMessage() {
        connection.send(content: "hello".data(using: .utf8), completion: .contentProcessed({error in
            if let error = error {
                print("error while sending hello: \(error)")
                return
            }
            print("sending hello succeeded")
            self.connection.receiveMessage {data, context, isComplete, error in
                if let error = error {
                    print("error while receiving reply: \(error)")
                    return
                }
                print("received:", data.flatMap{String(data: $0, encoding: .utf8)} ?? "undecodable data")
                self.sendMessage()
            }
        }))
    }
}

let client = ExampleClient()
client.run()

RunLoop.main.run()


Server:

import Foundation
import Network

class ExampleServer {
    var connections = [NWConnection]()
    lazy var listener: NWListener = {
        let listener = try! NWListener(using: .udp)
        
        listener.service = NWListener.Service(type: "_test._udp")
        listener.serviceRegistrationUpdateHandler = {serviceChange in
            switch serviceChange {
            case .add(let endpoint):
                switch endpoint {
                case let .service(name, _, _, _):
                    print("listening as name \(name)")
                default:
                    break
                }
            default:
                break
            }
            
        }
        listener.newConnectionHandler = {newConnection in
            print("Accepted:", newConnection)
            DispatchQueue.main.async {
                self.connections.append(newConnection)
            }
            newConnection.start(queue: DispatchQueue(label: "new client"))
            self.receive(on: newConnection)
        }
        return listener
    }()
    
    func run() {
        self.listener.start(queue: DispatchQueue(label: "server"))
    }
    
    func receive(on connection: NWConnection) {
        connection.receiveMessage {data, context, isComplete, error in
            if let error = error {
                print(error)
                return
            }
            print("received:", data.flatMap{String(data: $0, encoding: .utf8)} ?? "undecodable data")
            connection.send(content: "world".data(using: .utf8), completion: .contentProcessed({error in
                if let error = error {
                    print("error while sending data: \(error)")
                    return
                }
                print("sent reply")
                self.receive(on: connection)
            }))
        }
    }
}

let server = ExampleServer()
server.run()

RunLoop.main.run()


Network framework is not yet documented clearly and I'm not accustomed to use it, so there may be many points to improve.

But this code works steadily for a while...

Accepted Answer

But generally, infinite loop is something you should better avoid. Especially in your case, `loopForever() in your client will send too many UDP packets to be processed by the server in a short period.


Client:

import Foundation
import Network

let ServerName = "OOPer's mini"

class ExampleClient {
    lazy var connection: NWConnection = {
        let connection = NWConnection(
            to: .service(
                name: ServerName,
                type: "_test._udp",
                domain: "local",
                interface: nil
            ),
            using: .udp
        )
        
        connection.stateUpdateHandler = {newState in
            switch newState {
            case .ready:
                print("connection ready")
                self.sendMessage()
            case .failed(let error):
                print("client failed with error: \(error)")
            default:
                break
            }
        }
        
        return connection
    }()
    
    func run() {
        connection.start(queue: DispatchQueue(label: "client"))
    }
    
    func sendMessage() {
        connection.send(content: "hello".data(using: .utf8), completion: .contentProcessed({error in
            if let error = error {
                print("error while sending hello: \(error)")
                return
            }
            print("sending hello succeeded")
            self.connection.receiveMessage {data, context, isComplete, error in
                if let error = error {
                    print("error while receiving reply: \(error)")
                    return
                }
                print("received:", data.flatMap{String(data: $0, encoding: .utf8)} ?? "undecodable data")
                self.sendMessage()
            }
        }))
    }
}

let client = ExampleClient()
client.run()

RunLoop.main.run()


Server:

import Foundation
import Network

class ExampleServer {
    var connections = [NWConnection]()
    lazy var listener: NWListener = {
        let listener = try! NWListener(using: .udp)
        
        listener.service = NWListener.Service(type: "_test._udp")
        listener.serviceRegistrationUpdateHandler = {serviceChange in
            switch serviceChange {
            case .add(let endpoint):
                switch endpoint {
                case let .service(name, _, _, _):
                    print("listening as name \(name)")
                default:
                    break
                }
            default:
                break
            }
            
        }
        listener.newConnectionHandler = {newConnection in
            print("Accepted:", newConnection)
            DispatchQueue.main.async {
                self.connections.append(newConnection)
            }
            newConnection.start(queue: DispatchQueue(label: "new client"))
            self.receive(on: newConnection)
        }
        return listener
    }()
    
    func run() {
        self.listener.start(queue: DispatchQueue(label: "server"))
    }
    
    func receive(on connection: NWConnection) {
        connection.receiveMessage {data, context, isComplete, error in
            if let error = error {
                print(error)
                return
            }
            print("received:", data.flatMap{String(data: $0, encoding: .utf8)} ?? "undecodable data")
            connection.send(content: "world".data(using: .utf8), completion: .contentProcessed({error in
                if let error = error {
                    print("error while sending data: \(error)")
                    return
                }
                print("sent reply")
                self.receive(on: connection)
            }))
        }
    }
}

let server = ExampleServer()
server.run()

RunLoop.main.run()


Network framework is not yet documented clearly and I'm not accustomed to use it, so there may be many points to improve.

But this code works steadily for a while...

Network.framework nw_read_request_get_maximum_datagram_count
 
 
Q