Я пытаюсь создать простой эхо-сервер UDP, который отправляет обратно все входящие датаграммы с префиксом строки UTF8.

В моих попытках достичь этой цели мне удалось отправить обратно входящие данные, но когда я пытаюсь добавить к этим данным префикс строки: "You sent: ", я получаю сообщение об ошибке writeDataUnsupported

Это мой код:

Я сделал ChannelInboundHandler под названием Echo, и все, что он делает: для каждой входящей датаграммы он отправляет строку "You sent: ", а затем данные входящей датаграммы.

final class Echo: ChannelInboundHandler {
    typealias   InboundIn = ByteBuffer
    typealias OutboundOut = ByteBuffer

    var wroteResponse = false
    static let response = "You sent: ".data(using: .utf8)!

    func channelRead(ctx: ChannelHandlerContext, data: NIOAny) {
        if !wroteResponse {
            var buffer = ctx.channel.allocator.buffer(capacity: Echo.response.count)
            buffer.write(bytes: Echo.response)
            ctx.write(self.wrapOutboundOut(buffer), promise: nil)
            wroteResponse = true
        }
        ctx.write(data, promise: nil)
    }

    func channelReadComplete(ctx: ChannelHandlerContext) {
        ctx.flush()
        wroteResponse = false
    }
}

Затем я создал группу однопоточного цикла событий и назначил ей загрузочную программу дейтаграммы. Затем я привязал начальную загрузку к порту 4065.

let 🔂 = MultiThreadedEventLoopGroup(numThreads: 1)
let bootstrap = DatagramBootstrap(group: 🔂)
    .channelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
    .channelInitializer { $0.pipeline.add(handler: Echo()) }
defer {
    try! 🔂.syncShutdownGracefully()
}


try bootstrap
    .bind(host: "127.0.0.1", port: 4065)
    .wait()
    .closeFuture
    .wait()

Почему я всегда получаю это writeDataUnsupported при попытке отправить строку: "You sent: "?

4
Damiaan Dufaux 13 Мар 2018 в 23:23

2 ответа

Лучший ответ

Для DatagramChannel вам нужно обернуть ByteBuffer в AddressEnvelope. Это также означает, что ваш ChannelInboundHandler должен работать с AddressedEnvelope<ByteBuffer>.

2
Norman Maurer 20 Мар 2018 в 19:48

Чтобы заставить ChannelInboundHandler работать с AddressedEnvelope<ByteBuffer>, как предлагает Норман Маурер, вы можете переписать Echo так, чтобы оно выглядело больше:

final class Echo: ChannelInboundHandler {
    typealias  InboundIn  = AddressedEnvelope<ByteBuffer>
    typealias OutboundOut = AddressedEnvelope<ByteBuffer>

    static let response = "You sent: ".data(using: .utf8)!

    func channelRead(ctx: ChannelHandlerContext, data: NIOAny) {
        var incomingEnvelope = unwrapInboundIn(data)
        var buffer = ctx.channel.allocator.buffer(capacity: Echo.response.count + incomingEnvelope.data.readableBytes)
        buffer.write(bytes: Echo.response)
        buffer.write(buffer: &incomingEnvelope.data)

        let envelope = AddressedEnvelope(remoteAddress: incomingEnvelope.remoteAddress, data: buffer)
        ctx.write(wrapOutboundOut(envelope), promise: nil)
    }

    func channelReadComplete(ctx: ChannelHandlerContext) {
        ctx.flush()
    }
}
2
Damiaan Dufaux 21 Мар 2018 в 07:24