Java Netty object echo示例服务器channelRead方法不适用于我的自定义对象
我最近开始尝试使用Netty来创建视频游戏服务器/客户端关系。我正在使用Netty 4.1.X源提供的Netty“Object Echo”示例。客户机和服务器包含在单独的项目中。“VersionInfo”类在服务器和客户端项目中都可用,但具有不同的包名称 我遇到的问题是,当我将自定义对象从客户端发送到服务器时,它没有被接收。然而,如果我发送一个字符串对象,它就可以完美地工作 服务器:Java Netty object echo示例服务器channelRead方法不适用于我的自定义对象,java,object,echo,netty,pojo,Java,Object,Echo,Netty,Pojo,我最近开始尝试使用Netty来创建视频游戏服务器/客户端关系。我正在使用Netty 4.1.X源提供的Netty“Object Echo”示例。客户机和服务器包含在单独的项目中。“VersionInfo”类在服务器和客户端项目中都可用,但具有不同的包名称 我遇到的问题是,当我将自定义对象从客户端发送到服务器时,它没有被接收。然而,如果我发送一个字符串对象,它就可以完美地工作 服务器: public class Server { private int port; pub
public class Server {
private int port;
public Server(int port) {
this.port = port;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ServerChannelInitializer())
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
// Bind and start to accept incoming connections.
ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
// Wait until the server socket is closed.
// In this example, this does not happen, but you can do that to gracefully
// shut down your server.
channelFuture.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) {
try {
new Server(1337).run();
} catch (Exception e) {
e.printStackTrace();
}
}
}
服务器通道初始值设定项:
public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> {
public void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(new ObjectEncoder());
pipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
pipeline.addLast(new ObjectEchoServerHandler());
}
}
public class ClientChannelInitializer extends ChannelInitializer<SocketChannel> {
@Override
public void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(new ObjectEncoder());
pipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
pipeline.addLast(new ObjectEchoClientHandler());
}
}
VersionInfo类(在客户端和服务器上,但包名不同):
现在转到客户机代码:
public class Client {
public static void main(String[] args) throws Exception {
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(workerGroup);
bootstrap.channel(NioSocketChannel.class);
bootstrap.option(ChannelOption.TCP_NODELAY, true);
bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
bootstrap.handler(new ClientChannelInitializer());
// Start the client.
ChannelFuture channelFuture = bootstrap.connect("localhost", 1337).sync(); // (5)
// Wait until the connection is closed.
channelFuture.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
}
}
}
ClientChannelInitializer:
public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> {
public void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(new ObjectEncoder());
pipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
pipeline.addLast(new ObjectEchoServerHandler());
}
}
public class ClientChannelInitializer extends ChannelInitializer<SocketChannel> {
@Override
public void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(new ObjectEncoder());
pipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
pipeline.addLast(new ObjectEchoClientHandler());
}
}
在ObjectEchoClientHandler channelActive方法中发送字符串可以正常工作。发送自定义POJO/对象不会调用ObjectEchoServerHandler channelRead方法
这可能是什么原因造成的
编辑#1:根据Nicholas的建议在下面添加日志文本。很抱歉在日志调试过程中出现了blockquote。堆栈溢出编辑器不允许我在没有它的情况下提交它
VersionInfo类已更改,以反映相同的包名称。新类别:
package com.nettytest.iocommon;
public class VersionInfo {
public String version = "1.0.0";
public boolean versionChecked = false;
}
发送自定义Pojo后的客户端输出
2017年3月22日下午1:09:43 io.netty.handler.logging.LoggingHandler
信道注册严重:[id:0x237af0b8]于2017年3月22日注册
下午1:09:43 io.netty.handler.logging.LoggingHandler连接严重:
[id:0x237af0b8]连接:本地主机/127.0.0.1:1337[客户端]正在发送
版本信息2017年3月22日下午1:09:43
io.netty.handler.logging.LoggingHandler通道活动严重:[id:
0x237af0b8,L:/127.0.0.1:52830-R:localhost/127.0.0.1:1337]处于活动状态2017年3月22日下午1:09:43 io.netty.handler.logging.LoggingHandler写入 严重:[id:0x237af0b8,L:/127.0.0.1:52830- R:localhost/127.0.0.1:1337]写入: com.nettytest.iocommon。VersionInfo@7544bac2017年3月22日下午1:09:43 io.netty.handler.logging.LoggingHandler刷新严重:[id: 0x237af0b8,L:/127.0.0.1:52830-R:localhost/127.0.0.1:1337]刷新 接收自定义Pojo后的服务器输出 2017年3月22日下午1:09:43 io.netty.handler.logging.LoggingHandler channelRegistered[服务器]通道活动严重:[id:0xcdffaece, L:/127.0.0.1:1337-R:/127.0.0.1:52830]于2017年3月22日注册 下午1:09:43 io.netty.handler.logging.LoggingHandler通道活动
严重:[id:0xCDF,L:/127.0.0.1:1337-R:/127.0.0.1:52830] 活跃的
调试的一种方法是向服务器管道中添加一个。大概是这样的:
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.logging.LogLevel;
....
final LoggingHandler loggingHandler = new LoggingHandler(getClass(),
LogLevel.ERROR);
....
pipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
pipeline.addLast("logger", loggingHandler);
pipeline.addLast(new ObjectEchoServerHandler());
....
我最初的怀疑是,由于您传递的pojo类型在客户端和服务器上具有不同的包名(这意味着它们不是同一个类),因此客户端上的ObjectDecoder失败,因为它无法在其类路径中找到该类。要使其正常工作,该类必须存在于服务器和客户端类路径中。我已按照您的建议添加了记录器,并使VersionInfo类的包名与两个项目完全相同。我已经用记录器的详细信息更新了问题。不幸的是,堆栈溢出编辑器认为调试信息是未格式化的代码。因为只有相同的包名仍然不起作用,所以我更进一步。我将VersionInfo类放在一个单独的项目中。然后,我将该项目编译为jar文件。然后,我将该jar文件作为外部库添加到客户机和服务器项目中。将JAR添加到项目类路径中。这两个项目都认可这个类,但它仍然不起作用。而且记录器的输出信息不是很丰富,很奇怪。我将尝试从您提供的代码中复制。我不是测试的目标,但是VersionInfo类是否需要实现可序列化?字符串does和so does List(列表在正式的ObjectEcho示例中使用)。这可能就是问题所在。如果我没记错的话,您需要实现serializeable来手工编写网络代码。同时,感谢您迄今为止的所有帮助!正如我在前面的评论中提到的,我需要实现序列化。这样做修复了问题,项目现在按预期运行。谢谢你的帮助!
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.logging.LogLevel;
....
final LoggingHandler loggingHandler = new LoggingHandler(getClass(),
LogLevel.ERROR);
....
pipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
pipeline.addLast("logger", loggingHandler);
pipeline.addLast(new ObjectEchoServerHandler());
....