【问题标题】:Add multiple channel pipeline handlers in SwiftNIO similarly as Java Netty在 SwiftNIO 中添加多个通道管道处理程序,类似于 Java Netty
【发布时间】:2019-04-25 03:03:26
【问题描述】:

我正在探索如何在 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 中获得这些?

【问题讨论】:

    标签: ios swift swift-nio


    【解决方案1】:

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

    • IdleStateHandler: availableimport 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)
                }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 2016-03-24
      • 1970-01-01
      • 1970-01-01
      • 2019-04-25
      • 2021-03-18
      • 2020-09-28
      • 2021-09-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多