Message du client au serveur

C’est en fait mon premier post ici et j’essaie de le comprendre depuis un certain temps, mais j’appelle enfin le drapeau et vais essayer d’obtenir de l’aide sur ce sujet.

J’ai donc un client et un serveur qui ont été modélisés d’après le client / serveur d’écho et le client / serveur de discussion sécurisé. La partie SSL du chat ne m’intéresse pas et j’utilise l’écho uniquement pour m’assurer de recevoir des réponses du client / serveur. Je vais append tout le code pertinent au bas de ce post. Le problème que je rencontre en ce moment est que je peux envoyer un message du serveur au client lors de la connexion du client, mais je ne peux pas envoyer de message du client au serveur sur le serveur qui envoie le message initial au client. Le message envoyé par le serveur est:

Welcome to the server! 

Le message du client est

 test 

Je devrais savoir que j’ai reçu le message du client car il devrait revenir en arrière

 [You] test 

Je sais que le serveur voit le client et qu’il me donne des mises à jour de statut, mais je ne peux pas envoyer de message au serveur pour une raison quelconque. Maintenant pour une question sur le dessus de … Par hasard, j’utilise actuellement un SsortingngDecoder et SsortingngEncoder comme décodeur et encodeur … Si vous créez un jeu (ce que je fais) et que vous aurez des choses comme connexions, mouvements de joueurs, mises à jour du monde, etc. Je sais que je vois beaucoup de stream d’octets et, dans mon cours de programmation que nous avons suivi, nous avons abordé la manipulation des stream d’octets, mais je ne suis toujours pas à l’aise à 100% avec eux. Si les stream d’octets sont le meilleur / meilleur moyen de le faire, quelqu’un peut-il expliquer en détail comment il fonctionne pour manipuler un stream d’octets afin de pouvoir gérer différents éléments.

Comme indiqué précédemment, tout commence chez le client:

 public class Client { public Client() { // Initialize the window GameWindow.init(); // Initialize the server connection ClientHandler.init(); } public static void main(Ssortingng[] 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()); } } 

Et enfin le 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.ssortingng.SsortingngDecoder; import org.jboss.netty.handler.codec.ssortingng.SsortingngEncoder; 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 SsortingngDecoder()); pipeline.addLast("encoder", new SsortingngEncoder()); pipeline.addLast("handler", new ClientHandler()); return pipeline; } } 

Du côté serveur:

 package simple.server; public class Server { public static void main(Ssortingng[] 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.ssortingng.SsortingngDecoder; import org.jboss.netty.handler.codec.ssortingng.SsortingngEncoder; 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 SsortingngDecoder()); pipeline.addLast("encoder", new SsortingngEncoder()); pipeline.addLast("handler", new ServerChannelHandler()); return pipeline; } } 

Une fois encore, j’apprécie toute l’aide que vous pouvez m’apporter pour comprendre cela.

Vous avez oublié d’append \r\n à "test" . Ce devrait être: channel.write("test\r\n") .`

Comme vous le voyez dans le pipeline, la partie de décodage est composée de deux gestionnaires. La première fractionne et fusionne les données reçues en une seule ligne de chaîne et supprime la ligne se terminant par celle-ci. La seconde convertit la seule ligne de chaîne en java.lang.Ssortingng .

Du côté de l’encodage, il n’y a qu’un seul gestionnaire, qui convertit un java.lang.Ssortingng en ByteBuf , et c’est tout ce qu’il fait. Peut-être vaut-il mieux introduire un gestionnaire appelé LineEncoder , LineDecoder et LineCodec qui effectue le travail généralement attendu: https://github.com/netty/netty/issues/1811

NE nouvelle chaîne (“test”). Ce serait plus générique. Répondez à la dernière partie de votre post- Créez un object de classe avec toutes vos informations telles que les connexions, les mouvements du joueur, etc. dans l’object et transmettez-le. Assurez-vous que votre classe implémente Serializable. Le passer en tant que chaîne est un mauvais moyen de le faire car je suppose qu’il deviendra une sorte de code codé en dur. Le code client ressemblera à ceci:

 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); 

Le code serveur ressemblera à ceci:

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

Le gestionnaire de serveur sera:

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