0

我正在探索如何在 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”类似的类。我怎样才能在 SwiftNIO 中获得这些?

4

1 回答 1

3

好吧,让我来看看你在 Netty 中添加到管道中的所有处理程序:

  • IdleStateHandler从包装import NIO中获得swift-nio
  • LengthFieldBasedFrameDecoder:现在在 PR 中,但很快就会import NIOExtrasswift-nio-extras包中获得
  • ProtobufDecoder, LengthFieldPrepender, ProtobufEncoder: 所有当前不可用但易于实现:

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)
            }
        }
    }
于 2018-11-22T15:12:33.263 回答