Netty Client vers le Serveur de message
C'est mon premier post ici et j'ai essayé de comprendre cela pour un certain temps, mais je suis enfin en appelant le drapeau et va essayer d'obtenir un peu d'aide sur ce sujet.
Donc, j'ai un Client et un Serveur qui a été modélisé d'après l'écho et du client/serveur sécurisé de chat client/serveur. Je ne suis pas intéressé par la SSL partie de la discussion et de l'utilisation de l'echo juste pour s'assurer que je reçois des réponses et à partir du client/serveur. Je vais ajouter tout le code en bas de ce post. Le problème que je reçois à l'instant, c'est que je peux envoyer un message à partir du serveur vers le client sur le client qui se connecte mais je ne suis pas en mesure d'envoyer un message au client pour le Serveur sur le serveur envoi au client, le message initial. Le message envoyé à partir du serveur est:
Welcome to the server!
Le message du client est
test
Je dois savoir que j'ai le message au client de cause, il doit renvoyer
[You] test
Je sais que le Serveur voit le Client et il me donne des mises à jour de statut, mais je ne peux pas envoyer un message au serveur pour une raison quelconque. Maintenant, une question sur le dessus de cela... Par chance, je suis actuellement en utilisant un StringDecoder et StringEncoder, le Décodeur et Encodeur... Si vous êtes de faire un jeu (qui est ce que je fais) et vous aurez des connexions, joueur de mouvements, le monde des mises à jour, etc... est d'envoyer des Chaînes de la meilleure façon de le faire? Je sais, je vois beaucoup avec l'octet cours d'eau et dans ma programmation de classe, je suis allé à travers, nous avons abordé la manipulation de flux d'octets, mais je suis toujours pas à 100% à l'aise avec eux. Si l'octet, les flux sont les mieux/meilleur moyen pour faire cela, alors quelqu'un peut-il expliquer en détail comment ça fonctionne pour manipuler un flux d'octets pour être en mesure de gérer les différents éléments.
Comme l'a dit avant c'est le début de tout dans le client:
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 < 2 || args.length > 3) {
System.err.println("Usage: " + Client.class.getSimpleName() + " <host> <port> [<first message size>]");
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 la 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;
}
}
Côté Serveur:
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;
}
}
Une fois de plus tout le monde j'apprécie toute l'aide que vous pouvez me donner sur cette compréhension.
Assurez-vous désolé ne sais pas si quelqu'un aurait voulu, mais je dois aussi ajouter que je peux Telnet localhost 45000 à mon serveur et il le fait comme prévu..... Je suis de l'édition de l'original post pour ajouter dans le code serveur.
Toute personne en mesure de m'aider avec ce problème?
OriginalL'auteur Maxs728 | 2012-12-17
Vous devez vous connecter pour publier un commentaire.
Vous avez oublié d'ajouter
\r\n
à"test"
. Il doit être:channel.write("test\r\n")
.`Comme vous le voyez sur le pipeline, le décodage de la partie est composée de deux gestionnaires. La première se divise et fusionne les données reçues dans une seule ligne de chaîne et les bandes de la fin de ligne. Le second convertit la seule ligne de chaîne en
java.lang.String
.Sur l'encodage côté, il n'y a qu'un seul gestionnaire, qui convertit un
java.lang.String
enByteBuf
, et c'est tout ce qu'il fait. Peut-être qu'il est préférable d'introduire une fonction appeléeLineEncoder
,LineDecoder
, etLineCodec
qui ne l'habitude d'emploi: https://github.com/netty/netty/issues/1811Je ne pouvais pas avoir deviné cela. Comportement étrange, est-il une raison pour cela?
Mise à jour de la réponse de répondre aux questions dans les commentaires.
OriginalL'auteur trustin
N'new String("test"). Ce serait plus générique.
La réponse à la dernière partie de votre post - Créer un Objet de Classe avec toutes vos informations, comme les Connexions, le Joueur de mouvements etc. dans l'Objet et le passer. Assurez-vous que votre classe implémente Serializable.
Passer en tant que Chaîne de caractères est une mauvaise façon de le faire, car je suppose qu'il va devenir sorte de codé en dur.Client code ressemblera à ceci:
Serveur de code ressemblera à ceci:
Serveur Gestionnaire sera:
Je l'utilise et ça marche. À l'Aide d'un ObjectEncoder et ObjectDecoder convient le plus à son cas d'utilisation plutôt que la Chaîne du Décodeur. Cela faisait partie de sa question. Bien qu'il est accepté de répondre à son problème d'origine, j'ai proposé une approche radicalement différente.
Si vous êtes en utilisant cela et cela fonctionne, pouvez-vous mettre un extrait de code pour illustrer? Le format actuel de votre réponse n'aide pas vraiment.
Mettant en évidence la partie de la question je répondais: "si vous êtes de faire un jeu (qui est ce que je fais) et vous aurez des connexions, joueur de mouvements, le monde des mises à jour, etc... est d'envoyer des Chaînes de la meilleure façon de le faire? "
est-ce que mon code a certains défauts ou suis-je pas compris la question?
OriginalL'auteur naves