Netty客户端到服务器消息

这实际上是我在这里的第一篇文章,我一直试图弄清楚这一段时间,但我终于打电话给旗帜并试图在这个主题上得到一些帮助。

所以我有一个客户端和一个服务器,它是在echo客户端/服务器和安全聊天客户端/服务器之后建模的。 我对聊天的SSL部分并不感兴趣,只是为了确保我收到客户端/服务器的响应。 我将在本文的底部添加所有相关代码。 我目前遇到的问题是,我可以在客户端连接时从服务器向客户端发送消息,但是在服务器向客户端发送初始消息时,我无法从客户端向服务器发送消息。 从服务器发送的消息是:

Welcome to the server! 

来自客户端的消息是

 test 

我应该知道我从客户端收到了消息,因为它应该回显

 [You] test 

我知道服务器看到客户端,它给我状态更新但我不能出于某种原因向服务器发送消息。 现在提出一个问题……有一次我正在使用StringDecoderStringEncoder作为解码器和编码器…如果你正在制作一个游戏(这就是我正在做的事情)你会有类似的东西登录,玩家动作,世界更新等……发送Strings是最好的方法吗? 我知道我看到很多字节流,在我的编程课中,我经历过触摸操作字节流,但我仍然不是很满意它们。 如果字节流是更好/最好的方法,那么有人可以详细解释如何操作字节流以处理不同的项目。

如前所述,这是客户端中所有内容的开始:

 public class Client { public Client() { // Initialize the window GameWindow.init(); // Initialize the server connection ClientHandler.init(); } public static void main(String[] args) throws Exception { // Set a default server address if one isn't specified in the arguments if (args.length  3) { System.err.println("Usage: " + Client.class.getSimpleName() + "   []"); System.err.println("Using default values."); } else { // Parse arguments Settings.host = args[0]; Settings.port = Integer.parseInt(args[1]); } // start client new Client(); } 

ClientHandler中:

 package simple.client.net; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.jboss.netty.channel.WriteCompletionEvent; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import simple.client.Settings; public class ClientHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger(ClientHandler.class.getName()); public static Channel channel; public ClientHandler() { } public static void init() { // Configure the client. ClientBootstrap bootstrap = new ClientBootstrap(new NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Set up the pipeline factory. bootstrap.setPipelineFactory(new ClientPipelineFactory()); // Start the connection attempt. ChannelFuture future = bootstrap.connect(new InetSocketAddress(Settings.host, Settings.port)); // Wait until the connection is closed or the connection attempt fails. channel = future.awaitUninterruptibly().getChannel(); // This is where the test write is <<------ ChannelFuture test = channel.write("test"); if (!future.isSuccess()) { future.getCause().printStackTrace(); bootstrap.releaseExternalResources(); return; } } @Override public void channelBound(ChannelHandlerContext ctx, ChannelStateEvent e) { System.out.println("Bound: " + e.getChannel().isBound()); } @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) { System.out.println("Connected: " + e.getChannel().isConnected()); System.out.println("Connected: " + e.getChannel().getRemoteAddress()); } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) { System.out.println("Closed: " + e.getChannel()); } @Override public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) { System.out.println("Disconnected: " + e.getChannel()); } @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) { System.out.println("Open: " + e.getChannel().isOpen()); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) { System.out.println("Error: " + e.getCause()); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) { System.out.println("Message: " + e.getMessage()); } } 

最后是ClientPipeline:

 package simple.client.net; import static org.jboss.netty.channel.Channels.*; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.Delimiters; import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; public class ClientPipelineFactory implements ChannelPipelineFactory { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("encoder", new StringEncoder()); pipeline.addLast("handler", new ClientHandler()); return pipeline; } } 

服务器端:

 package simple.server; public class Server { public static void main(String[] args) throws Exception { ServerChannelHandler.init(); } } 

ServerChannelHandler:

 package simple.server; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import java.util.logging.Logger; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.channel.group.ChannelGroup; import org.jboss.netty.channel.group.DefaultChannelGroup; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; public class ServerChannelHandler extends SimpleChannelHandler { private static final Logger logger = Logger.getLogger(ServerChannelHandler.class.getName()); private static ChannelGroup channels; private static ServerBootstrap bootstrap; public ServerChannelHandler() { } /** * Initialize the Server Channel Handler */ public static void init() { // create a channels group to add incoming channels to channels = new DefaultChannelGroup(); // create the server bootstrap (fancy word for pre-made server setup) bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // set the server pipeline factory bootstrap.setPipelineFactory(new ServerPipelineFactory()); // server settings bootstrap.setOption("keepAlive", true); // bind the server to the port bootstrap.bind(new InetSocketAddress(Settings.PORT_ID)); } @Override public void channelBound(ChannelHandlerContext ctx, ChannelStateEvent e) { System.out.println("Bound: " + e.getChannel()); } @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) { System.out.println("Connected: " + e.getChannel()); channels.add(e.getChannel()); e.getChannel().write("Welcome to the test server!\n\r"); } @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) { System.out.println("Closed: " + e.getChannel()); } @Override public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) { System.out.println("Disconnected: " + e.getChannel()); } @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) { System.out.println("Open: " + e.getChannel()); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) { System.out.println("Error: " + e.getCause()); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) { System.out.println("Message: " + e.getMessage()); for (Channel c : channels) { if (e.getMessage().equals("shutdown")) { shutdown(); } if (c != e.getChannel()) { c.write("[" + e.getChannel().getRemoteAddress() + "] " + e.getMessage() + "\n\r"); } else { c.write("[You] " + e.getMessage() + "\n\r"); } } } /** * Shuts down the server safely */ public static final void shutdown() { channels.close(); bootstrap.releaseExternalResources(); System.exit(0); } } 

ServerPipelineFactory:

 package simple.server; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.Delimiters; import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; import simple.server.decoder.Decoder; import simple.server.encoder.Encoder; public class ServerPipelineFactory implements ChannelPipelineFactory { @Override public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("encoder", new StringEncoder()); pipeline.addLast("handler", new ServerChannelHandler()); return pipeline; } } 

我再次感谢所有帮助,你可以让我理解这一点。

你忘了将\r\n附加到"test" 。 它应该是: channel.write("test\r\n") `

从管道中可以看出,解码部分由两个处理程序组成。 第一个将接收到的数据拆分并合并为一行字符串,并从中结束行。 第二个将单行字符串转换为java.lang.String

在编码方面,只有一个处理程序,它将java.lang.String转换为ByteBuf ,就是这样。 也许最好引入一个名为LineEncoderLineDecoderLineCodec的处理程序来执行通常预期的工作: https : //github.com/netty/netty/issues/1811

做新的字符串(“测试”)。 那将是更通用的。 回答你的后期部分 – 用对象中的登录,玩家动作等所有信息创建一个类对象并传递它。 确保您的类实现Serializable。 将它作为String传递是一种不好的方法,因为我认为它将成为一种硬编码。客户端代码将如下所示:

 ChannelPipeline p = ch.pipeline(); p.addLast( new ObjectEncoder(), new ObjectDecoder(ClassResolvers.cacheDisabled(getClass().getClassLoader())), new ClientHandler()); } }); // Start the connection attempt. ChannelFuture f= b.connect(host, port); channel=f.awaitUninterruptibly().channel(); TestObj obj= new TestObj(); channel.writeAndFlush(obj); 

服务器代码如下所示:

  ChannelPipeline p = ch.pipeline(); p.addLast( new ObjectEncoder(), new ObjectDecoder(ClassResolvers.cacheDisabled(getClass().getClassLoader())), new DiscardServerHandler()); } 

服务器处理程序将是:

 @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { System.out.println("channelRead"+((TestObj)msg).getCurrency()); }