SwiftNIO: отправка и получение UDP-трансляции - PullRequest
0 голосов
/ 24 октября 2019

Я пытаюсь построить TCP-сервер с SwiftNIO. Сервер запускается в сети, но клиенты не знают IP-адрес. Поэтому я хочу запустить UDP-сервер, и если клиенты приходят, он отправляет широковещательное сообщение в сеть. Сервер получит и ответит, так что клиент теперь знает IP-адрес.

Возможно ли создать что-то подобное с SwiftNIO?

1 Ответ

1 голос
/ 25 октября 2019

Да, это возможно, и в SwiftNIO не так много поддержки, чтобы сделать это легко. Ниже приведен прокомментированный пример, который будет отправлять HELLO WORLD раз в секунду на широковещательный адрес en0 и порт 37020.

import NIO

let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
defer {
    try! group.syncShutdownGracefully()
}

let matchingInterfaces = try System.enumerateInterfaces().filter {
    // find an IPv4 interface named en0 that has a broadcast address.
    $0.name == "en0" && $0.broadcastAddress != nil
}

guard let en0Interface = matchingInterfaces.first, let broadcastAddress = en0Interface.broadcastAddress else {
    print("ERROR: No suitable interface found. en0 matches \(matchingInterfaces)")
    exit(1)
}

// let's bind the server socket
let server = try! DatagramBootstrap(group: group)
    // enable broadast
    .channelOption(ChannelOptions.socket(SOL_SOCKET, SO_BROADCAST), value: 1)
    .bind(to: en0Interface.address)
    .wait()
print("bound to \(server.localAddress!)")

var buffer = server.allocator.buffer(capacity: 32)
buffer.writeString("HELLO WORLD!")

var destAddr = broadcastAddress
destAddr.port = 37020 // we're sending to port 37020

// now let's just send the buffer once a second.
group.next().scheduleRepeatedTask(initialDelay: .seconds(1),
                                  delay: .seconds(1),
                                  notifying: nil) { task in
    server.writeAndFlush(AddressedEnvelope(remoteAddress: destAddr,data: buffer)).map {
        print("message sent to \(destAddr)")
    }.whenFailure { error in
        print("ERROR: \(error)")
        // and stop if there's an error.
        task.cancel()
        server.close(promise: nil)
    }
}

try server.closeFuture.wait()

В случае, если вы хотите связать с 0.0.0.0 и отправить на 255.255.255.255 Вы можете использовать это

import NIO

let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
defer {
    try! group.syncShutdownGracefully()
}

// let's bind the server socket
let server = try! DatagramBootstrap(group: group)
    // enable broadast
    .channelOption(ChannelOptions.socket(SOL_SOCKET, SO_BROADCAST), value: 1)
    .bind(to: .init(ipAddress: "0.0.0.0", port: 0))
    .wait()
print("bound to \(server.localAddress!)")

var buffer = server.allocator.buffer(capacity: 32)
buffer.writeString("HELLO WORLD!")

// we're sending to port 37020
let destPort = 37020
let destAddress = try SocketAddress(ipAddress: "255.255.255.255", port: destPort)

// now let's just send the buffer once a second.
group.next().scheduleRepeatedTask(initialDelay: .seconds(1),
                                  delay: .seconds(1),
                                  notifying: nil) { task in
    server.writeAndFlush(AddressedEnvelope(remoteAddress: destAddress, data: buffer)).map {
        print("message sent to \(destAddress)")
    }.whenFailure { error in
        print("ERROR: \(error)")
        // and stop if there's an error.
        task.cancel()
        server.close(promise: nil)
    }
}
try server.closeFuture.wait()
...