Camel和Netty:客户端 - 中介应用程序 - 服务器

时间:2017-12-23 11:49:28

标签: apache-camel netty

我正在使用Camel和Netty设置一个场景,客户端连接到服务器,中间有一个应用程序(只是一个名为Router的虚拟应用程序)。

SocketClient连接到路由器(端口53379),路由器连接服务器(端口53383)。问题是数据包永远不会到达服务器(它确实到达了路由器,我使用处理器对其进行了调试)。

如果我将SocketClient连接到Server,它可以正常工作。

感谢任何帮助。

完整来源

路由器:

public class Router {
    public static void main(String[] args) throws Exception {
        SimpleRegistry registry = new SimpleRegistry();
        registry.put("ByteArrayEncoder", new ByteArrayEncoder());
        registry.put("ByteArrayDecoder", new ByteArrayDecoder());

        CamelContext context = new DefaultCamelContext(registry);

        context.addRoutes(new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                from("netty4:tcp://localhost:53379?encoders=#ByteArrayEncoder&"
                        + "decoders=#ByteArrayDecoder"
                        + "&sync=true"
                        + "&keepAlive=true")
                .to("netty4:tcp://localhost:53383?encoders=#ByteArrayEncoder&"
                        + "decoders=#ByteArrayDecoder"
                        + "&sync=true"
                        + "&keepAlive=true");               
            }
        });

        context.start();
        while(true) {
            Thread.sleep(1000);
        }
    }
}

服务器:

public class Server {
    public static void main(String[] args) throws Exception {
        SimpleRegistry registry = new SimpleRegistry();
        registry.put("ByteArrayEncoder", new ByteArrayEncoder());
        registry.put("ByteArrayDecoder", new ByteArrayDecoder());

        CamelContext context = new DefaultCamelContext(registry);

        context.addRoutes(new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                from("netty4:tcp://localhost:53383?encoders=#ByteArrayEncoder&"
                        + "decoders=#ByteArrayDecoder"
                        + "&sync=true"
                        + "&keepAlive=true")
                .process(new Processor() {
                    public void process(Exchange exchange) throws Exception {
                        Message message = exchange.getIn();
                        System.out.println("from este_stub: " + message.getBody());
                        exchange.setOut(message);
                    }
                });
            }
        });

        context.start();
        while(true) {
            Thread.sleep(1000);
        }
    }
}

客户端:

public class SocketClient {
    public static void main(String[] args) throws UnknownHostException, IOException {
        Socket socket = new Socket("localhost", 53379);
        OutputStream simOutStream = socket.getOutputStream();
        BufferedInputStream simInStream = new BufferedInputStream(socket.getInputStream());        

        byte[] arr = new byte[] {1, 2, 3, 4, 5};
        simOutStream.write(arr, 0, arr.length);
        simOutStream.flush();


        byte[] resp = new byte[5];
        simInStream.read(resp, 0, resp.length);
        for(byte ar : resp)
            System.out.print(ar);

        socket.close();
    }
}

1 个答案:

答案 0 :(得分:3)

运行您共享的代码会在路由器类io.netty.channel.ChannelPipelineException: io.netty.handler.codec.bytes.ByteArrayDecoder is not a @Sharable handler, so can't be added or removed multiple times.

中出现以下错误

正如例外所述, ByteArrayDecoder 以及 ByteArrayEncoder 不是可共享的处理程序,因此也是错误的原因。从Sharable的javadoc中可以清楚地看出

  

表示可以在没有竞争条件的情况下多次将带注释的ChannelHandler的同一实例添加到一个或多个ChannelPipeline。如果未指定此批注,则每次将其添加到管道时都必须创建新的处理程序实例,因为它具有非共享状态,例如成员变量。

netty4的骆驼文档也在Camel netty4

指出了这一点

如下:

  

如果您的编码器或解码器不可共享(例如,它们具有@Shareable类注释),那么您的编码器/解码器必须实现org.apache.camel.component.netty.ChannelHandlerFactory接口,并返回一个新的实例。 newChannelHandler方法。这是为了确保编码器/解码器可以安全使用。如果不是这种情况,那么Netty组件将在何时记录WARN   创建端点。   Netty组件提供了一个org.apache.camel.component.netty.ChannelHandlerFactories工厂类,它有许多常用的方法。

因此,通过使用一些自定义编码器和解码器实现ChannelHandlerFactory并覆盖newChannelHandler来解决您的问题,如下所示:

public class CustomByteArrayDecoder实现ChannelHandlerFactory {

@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {

}

@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {

}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

}

@Override
public ChannelHandler newChannelHandler() {
    return new ByteArrayDecoder();
}

也类似于编码器。然后在路由器和服务器上进行适当的更改,如下所示:

SimpleRegistry registry = new SimpleRegistry();
registry.put("ByteArrayEncoder", new CustomByteArrayEncoder());
registry.put("ByteArrayDecoder", new CustomByteArrayDecoder());