我正在探索如何在SwiftNIO的通道管道中添加多个处理程序。在Java Netty中,我有以下代码:

@Component
public class NettyClientFilter extends ChannelInitializer<SocketChannel> {

    @Autowired
    private NettyClientHandler nettyClientHandler;

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline ph = ch.pipeline();

        ph.addLast(new IdleStateHandler(20, 10, 0));
        ph.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 4, 0, 4));

        ph.addLast(new ProtobufDecoder(IMessage.getDefaultInstance()));

        ph.addLast(new LengthFieldPrepender(4));
        ph.addLast(new ProtobufEncoder());
        ph.addLast("nettyClientHandler",nettyClientHandler);

    }
}

在SwiftNIO中,似乎没有类似的类“LengthFieldBasedFrameDecoder”、“ProtobufDecoder”、“LengthFieldPrepender”、“ProtobufEncoder”。我怎么能把那些放在迅捷酒店?

最佳答案

好吧,让我看看你在Netty中添加到管道中的所有处理程序:
IdleStateHandleravailable来自import NIO包的swift-nio
LengthFieldBasedFrameDecoder:现在in a PR但是很快就可以从import NIOExtras包获得swift-nio-extras
ProtobufDecoderLengthFieldPrependerProtobufEncoder:所有当前不可用但易于实现:
LengthFieldPrepender

    final class LengthFieldPrepender<IntType: FixedWidthInteger>: ChannelOutboundHandler {
        // we send send and receive ByteBuffers
        typealias OutboundIn = ByteBuffer
        typealias OutboundOut = ByteBuffer

        private let endianness: Endianness
        private var buf: ByteBuffer?

        init(type: IntType.Type = IntType.self, endianness: Endianness = .big) {
            self.endianness = endianness
        }

        func handlerAdded(ctx: ChannelHandlerContext) {
            self.buf = ctx.channel.allocator.buffer(capacity: 8)
        }

        func write(ctx: ChannelHandlerContext, data: NIOAny, promise: EventLoopPromise<Void>?) {
            let incomingData = self.unwrapOutboundIn(data)

            // we cache `self.buf` so we might get lucky and save an allocation here if the previous buffer has been fully written already
            self.buf!.clear()
            // write the length as the right type
            self.buf!.write(integer: IntType(incomingData.readableBytes), endianness: self.endianness)
            ctx.write(self.wrapOutboundOut(self.buf!), promise: nil)
            // write the actual data
            ctx.write(data, promise: promise)
        }
    }

ProtobufDecoder
    import SwiftProtobuf
    import NIOFoundationCompat // for ByteBuffer.readData

    final class ProtobufDecoder<Msg: SwiftProtobuf.Message>: ChannelInboundHandler {
        typealias InboundIn = ByteBuffer
        typealias InboundOut = Msg

        func channelRead(ctx: ChannelHandlerContext, data: NIOAny) {
            var buffer = self.unwrapInboundIn(data)
            let data = buffer.readData(length: buffer.readableBytes)!
            do {
                // pretty straightforward here, just call the message type's initialiser
                let req = try Msg(serializedData: data)
                ctx.fireChannelRead(self.wrapInboundOut(req))
            } catch {
                ctx.fireErrorCaught(error)
            }
        }
    }

ProtobufEncoder
    import NIOFoundationCompat
    import SwiftProtobuf

    final class ProtobufEncoder<Msg: SwiftProtobuf.Message>: ChannelOutboundHandler {
        typealias OutboundIn = Msg
        typealias OutboundOut = ByteBuffer

        private var buf: ByteBuffer?

        func handlerAdded(ctx: ChannelHandlerContext) {
            self.buf = ctx.channel.allocator.buffer(capacity: 4096)
        }

        func write(ctx: ChannelHandlerContext, data: NIOAny, promise: EventLoopPromise<Void>?) {
            let msg = self.unwrapOutboundIn(data)
            self.buf!.clear()
            do {
                // just use SwiftProtobuf's nice encoder
                self.buf!.write(bytes: try msg.serializedData())
                ctx.write(self.wrapOutboundOut(self.buf!), promise: promise)
            } catch {
                ctx.fireErrorCaught(error)
            }
        }
    }

07-28 09:55