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.

Accepted Reply

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...

Replies

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...