Jenish
Jenish

Reputation: 477

Swift UDP Connection Issue

protocol UDPListener {
    func handleResponse(_ client: UDPConnection, data: Data)
}

class UDPConnection{
    
    var connection: NWConnection?
    var listner: NWListener?
    var delegate: UDPListener?

    let parameters = NWParameters.udp
    
    // for connect with device
    func connect(withHost: NWEndpoint.Host, port: NWEndpoint.Port) {
        parameters.allowLocalEndpointReuse = true
        
        self.connection = NWConnection(host: withHost, port: port, using: parameters)
        self.connection?.stateUpdateHandler = { (newState) in
            switch (newState) {
            case .ready:
                print("connection ready")
            case .setup:
                print("connectionsetup")
            case .cancelled:
                print("connectioncancelled")
            case .preparing:
                print("connection Preparing")
            default:
                print("connection waiting or failed")
                
            }
        }
        self.connection?.start(queue: .global())
    }
    
    // for sending UDP string
    func sendUDP(_ content: String) {
        let contentToSendUDP = content.data(using: String.Encoding.utf8)
        self.connection?.send(content: contentToSendUDP, completion: NWConnection.SendCompletion.contentProcessed(({ (NWError) in
            if (NWError == nil) {
                print("Data was sent to UDP")
            } else {
                print("ERROR SEND! Error when data (Type: Data) sending. NWError: \n \(NWError!)")
            }
        })))
    }
    
    //for sending UDP data
    func sendUDP(_ content: Data) {
        self.connection?.send(content: content, completion: NWConnection.SendCompletion.contentProcessed(({ (NWError) in
            if (NWError == nil) {
                print("Data was sent to UDP")
            } else {
                print("ERROR Send! Error when data (Type: Data) sending. NWError: \n \(NWError!)")
            }
        })))
    }
    
    //////////////// UDP LISTNER /////////////////////

    func listenUDP(port: NWEndpoint.Port) {
        do {
            parameters.allowLocalEndpointReuse = true
            
            self.listner = try NWListener(using: parameters, on: port)
            self.listner?.stateUpdateHandler = {(newState) in
                switch newState {
                case .ready:
                    print("Listner ready")
                case .failed:
                    print("Listner failed")
                case .cancelled:
                    print("Listner cancelled")
                default:
                    break
                }
            }
            self.listner?.newConnectionHandler = {(newConnection) in
                newConnection.stateUpdateHandler = {newState in
                    switch newState {
                    case .ready:
                        print("new connection establish")
                        self.receive(on: newConnection)
                    case .failed:
                        print("new connection failed")
                    case .cancelled:
                        print("new connection cancelled")
                    default:
                        break
                    }
                }
                newConnection.start(queue: DispatchQueue(label: "new client"))
            }
        } catch {
            print("unable to create listener")
        }
        self.listner?.start(queue: .global())
    }
    
    func receive(on connection: NWConnection) {
        connection.receiveMessage { (data, context, isComplete, error) in
            if !isComplete {
                print("Not Complete")
            }
            if let error = error {
                print("Error in REceive: - ",error)
                return
            }
            if let data = data, !data.isEmpty {
//                let backToString = String(decoding: data, as: UTF8.self)
//                print("Received Data: ",backToString)
                
                guard self.delegate != nil else {
                    print("Error Receive: UDPClient response handler is nil")
                    return
                }
                
                print("Data receive in UDPConenction;")
                self.delegate?.handleResponse(self, data: data)
                
            }
        }
    }

}

Here I attached my UDP file that contains connections and listener of UDP.

When I send some data for the first time, it will send the data and receive the data.

But when I send data again, then data will be sent, but I am not getting data second time and onwards. Listner is not listning anymore. Data will be sent but listener is not listening.

If I close the application and run it again, same issue occurs. First time load the data (listener lister the data) but second time listener is not working.

What is the issue in my code ? I was trying so much but not resolving the issue. Please anyone that can solve my issue would be so grateful to me.

Thank you in advance.

Upvotes: 0

Views: 1268

Answers (1)

rderik
rderik

Reputation: 510

In your function receive you are using the NWConnection.receiveMessage if you check the documentation here:

https://developer.apple.com/documentation/network/nwconnection/3020638-receivemessage

You'll see that it schedules a single receive completion handler. That means that you'll have to do something to trigger it again. What I normally do is have a function like:

private func setupReceive() {
        connection.receive(minimumIncompleteLength: 1, maximumLength: MTU) { (data, _, isComplete, error) in
            if let data = data, !data.isEmpty {
                let message = String(data: data, encoding: .utf8)
                print("connection \(self.id) did receive, data: \(data as NSData) string: \(message ?? "-")")
                self.send(data: data)
            }
            if isComplete {
                self.connectionDidEnd()
            } else if let error = error {
                self.connectionDidFail(error: error)
            } else {
                self.setupReceive() // HERE I SET THE RECEIVE AGAIN
            }
        }
    }

That way, after processing the read, you end up setting up another single receive completion handler.

If you want to see a full example, you can check my article on using Network.framework here:

https://rderik.com/blog/building-a-server-client-aplication-using-apple-s-network-framework/

The example uses TCP instead of UDP, but it should give a general idea.

Upvotes: 1

Related Questions