我正在使用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();
}
}
答案 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());