SwiftNIO:发送和接收 UDP 广播

SwiftNIO: Send and receive UDP broadcast

我正在尝试使用 SwiftNIO 构建 TCP 服务器。服务器在网络中启动,但客户端不知道 ip 地址。因此,我也想启动一个 UDP 服务器,如果客户端出现,他会向网络发送一条广播消息。服务器将接收并应答,以便客户端现在知道 IP 地址。

是否可以使用 SwiftNIO 构建类似的东西?

是的,这是可能的,而且 SwiftNIO 中没有太多支持使这变得容易。 请参阅下面的注释示例,该示例将每秒发送一次 HELLO WORLDen0 的广播地址和端口 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.
    [=10=].name == "en0" && [=10=].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()