swiftsocketsudpmulticast

Swift multicast multiple connection to the same port


I have two applications installed on the same device and they trying to connect to a multicast group the first application has a succeed connection the second one has error : listener failed with error Group entered state failed(POSIXErrorCode(rawValue: 48): Address already in use) I thought that allowLocalEndpointReuse allows several clients to connect to the same port

but it doesn't work.

    let port = NWEndpoint.Port(portUdp) ?? NWEndpoint.Port(5353)
    let host = NWEndpoint.Host(urlUdp)
    guard let multicast = try? NWMulticastGroup(for:
     [ .hostPort(host: host, port: port) ])
     else {
         stateMultiCast = "Error with url and port"
     return
     }
    
    let parameters = NWParameters.udp
    parameters.allowLocalEndpointReuse = true
    parameters.allowLocalEndpointReuse
    let group = NWConnectionGroup(with: multicast, using: parameters)

    
    group.setReceiveHandler(maximumMessageSize: 16384, rejectOversizedMessages: true) 
  { (message, content, isComplete) in
        ....
    }
    
    group.stateUpdateHandler = { (newState) in
        print("Group entered state \(String(describing: newState))")
    }
    group.start(queue: .main)

How can i use the same port for several application so this application can receive all the same message sent by udp server ?

Thank you for your help


Solution

  • I found a solution different of multicast group that apple recommand :

    func setupMulticastSocket(urlUdp : String, portUdp : String) -> Int32 {

        let multicastAddress = urlUdp
        let multicastPort: UInt16 = UInt16(portUdp) ?? 0
        // Create a UDP socket
        let socketFileDescriptor = socket(AF_INET, SOCK_DGRAM, 0)
        guard socketFileDescriptor != -1 else {
            print("Failed to create socket")
            exit(1)
        }
        // Enable multicast loopback
        var loop: UInt32 = 1
        guard setsockopt(socketFileDescriptor, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, socklen_t(MemoryLayout<UInt32>.size)) != -1 else {
            print("Failed to enable multicast loopback")
            exit(1)
        }
        
        var reuseFlag: Int32 = 1
        let reuseOption = withUnsafePointer(to: &reuseFlag) { ptr in
            return UnsafeRawPointer(ptr).assumingMemoryBound(to: Int32.self)
        }
        
        if setsockopt(socketFileDescriptor, SOL_SOCKET, SO_REUSEPORT, reuseOption, socklen_t(MemoryLayout<Int32>.size)) == -1 {
            print("Error setting SO_REUSEPORT: \(String(describing: strerror(errno)))")
            return -1
        }
        
        if setsockopt(socketFileDescriptor, SOL_SOCKET, SO_REUSEADDR, reuseOption, socklen_t(MemoryLayout<Int32>.size)) == -1 {
            print("Error setting SO_REUSEADDR: \(String(describing: strerror(errno)))")
            return -1
        }
    
        // Bind the socket to a specific address and port
        var socketAddress = sockaddr_in()
        socketAddress.sin_len = __uint8_t(MemoryLayout<sockaddr_in>.size)
        socketAddress.sin_family = sa_family_t(AF_INET)
        socketAddress.sin_port = multicastPort.bigEndian
        socketAddress.sin_addr.s_addr = CFSwapInt32HostToBig(INADDR_ANY)
    
        withUnsafePointer(to: &socketAddress) { pointer in
            let bindResult = pointer.withMemoryRebound(to: sockaddr.self, capacity: 1) { addrPointer in
                bind(socketFileDescriptor, addrPointer, socklen_t(MemoryLayout<sockaddr_in>.size))
            }
            guard bindResult != -1 else {
                print("Failed to bind socket")
                exit(1)
            }
        }
    
        // Join the multicast group
        var multicastRequest = ip_mreq()
        multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastAddress)
        multicastRequest.imr_interface.s_addr = CFSwapInt32HostToBig(INADDR_ANY)
    
        guard setsockopt(socketFileDescriptor, IPPROTO_IP, IP_ADD_MEMBERSHIP, &multicastRequest, socklen_t(MemoryLayout<ip_mreq>.size)) != -1 else {
            print("Failed to join multicast group")
            exit(1)
        }
    
    
    
    
        
        return socketFileDescriptor
    }
    

    I call the function like that :

               let socketFD = setupMulticastSocket(urlUdp: urlUdp, portUdp: portUdp)
        if socketFD != -1 {
            print("Multicast socket set up successfully.")
        } else {
            print("Failed to set up multicast socket.")
        }
        let bufferSize = 1024
           var buffer = [UInt8](repeating: 0, count: bufferSize)
          // Reading message received
        while true {
            let bytesRead = recv(socketFD, &buffer, buffer.count, 0)
            if bytesRead > 0 {
                let messageData = Data(bytes: buffer, count: bytesRead)
                let hexString = messageData.reduce("") { $0 + String(format: "%02x", $1) }
                let decodedData = Data(hexString: hexString)!
                if let decodedData = Data(hexString: hexString){
                    newDataRsaReceived(decodedData ?? Data())
                }
            }
        }
    

    With this solution multiple client (application) can connect to the same port