【问题标题】:SwiftNIO: Send and receive UDP broadcastSwiftNIO:发送和接收 UDP 广播
【发布时间】:2020-02-21 05:35:54
【问题描述】:

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

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

【问题讨论】:

    标签: swift-nio


    【解决方案1】:

    是的,这也是可能的,SwiftNIO 中没有太多支持来简化此操作。 请参阅下面的注释示例,该示例将每秒向 en0 的广播地址和端口 37020 发送一次 HELLO WORLD

    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()
    

    【讨论】:

    • 非常感谢!我试过在同一台机器上运行,不幸的是客户端或服务器崩溃,因为端口已经在使用中。
    • 对不起,请忘记。经过其他一些测试后,我不得不重新启动我的机器;)现在它可以工作了。我尝试写一个完整的例子并放到Github上
    • @Lupurus 太棒了。顺便说一句,如果您知道您的广播地址,您也可以删除大部分代码,然后执行remoteAddress: try! SocketAddress(ipAddress: "192.168.1.255", port: destPort)。但在大多数情况下,用户希望广播到“接口”,因此我包含了代码。
    • 我仍然需要时间,因为 - 我不知道为什么 - 它只适用于 SwiftNIO
    • 顺便说一下,服务器需要绑定到“0.0.0.0”(但正如我所说,它只适用于版本
    猜你喜欢
    • 2021-07-30
    • 1970-01-01
    • 2013-05-22
    • 2012-06-05
    • 2015-03-14
    • 2018-02-27
    • 1970-01-01
    • 2011-10-02
    • 1970-01-01
    相关资源
    最近更新 更多