2012-12-17 12 views
10

Dies ist eigentlich mein erster Beitrag hier und ich habe versucht, dies für eine Weile herauszufinden, aber ich rufe endlich die Flagge und werde versuchen, etwas Hilfe zu diesem Thema zu bekommen.Netty Client to Server Nachricht

Also ich habe einen Client und einen Server, der nach dem Echo-Client/Server und dem sicheren Chat-Client/Server modelliert wurde. Ich bin nicht am SSL-Teil des Chats interessiert und benutze das Echo nur um sicherzustellen, dass ich Antworten auf und von dem Client/Server bekomme. Ich werde alle relevanten Code am Ende dieses Beitrags hinzufügen. Das Problem, das ich im Moment bekomme, ist, dass ich eine Nachricht vom Server an den Client senden kann, wenn der Client eine Verbindung herstellt, aber ich kann keine Nachricht vom Client an den Server senden, wenn der Server die erste Nachricht sendet. Die Nachricht von dem Server gesendet wird, ist:

Welcome to the server! 

Die Nachricht von dem Client ist

test 

ich wissen sollte, dass ich die Nachricht von dem Client bekam Ursache es

[You] test 
zurück echo sollte

Ich weiß, dass der Server den Client sieht und es gibt mir Status-Updates, aber ich kann aus irgendeinem Grund keine Nachricht an den Server senden. Nun zu einer Frage dazu ... Ich benutze momentan einen StringDecoder und StringEncoder als Decoder und Encoder ... Wenn Sie ein Spiel machen (was ich gerade mache) und Sie wird Dinge wie Logins, Spielerbewegungen, Weltupdates usw. haben ... sendet Strings den besten Weg, dies zu tun? Ich weiß, ich sehe viel mit Byte-Streams und in meiner Programmierklasse, die ich durchlaufen habe, haben wir versucht, Byteströme zu manipulieren, aber ich bin immer noch nicht 100% ig damit zufrieden. Wenn Byte-Streams der bessere/beste Weg sind, dies zu tun, dann kann jemand bitte etwas genauer erklären, wie es funktioniert, einen Byte-Strom zu manipulieren, um verschiedene Dinge handhaben zu können.

Wie bereits erwähnt, bevor dies der Beginn von allem im Client ist:

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

Und schließlich die 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; 
} 

} 

Server Side:

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

Wieder einmal jeder, den ich jede Hilfe dankbar du mich auf das Verständnis dieses geben kann.

+0

Irgendwelche serverseitigen Code? – Peter

+0

Sure Entschuldigung wusste nicht, ob jemand es gewollt hätte, aber ich sollte auch hinzufügen, dass ich Telnet localhost 45000 zu meinem Server tun kann und es wie erwartet dort tut ..... Ich bearbeite den ursprünglichen Beitrag, um in den Server hinzuzufügen Code. – Maxs728

+0

Kann mir jemand bei diesem Problem helfen? – Maxs728

Antwort

4

Sie haben vergessen, \r\n an "test" anzufügen. Es sollte sein: channel.write("test\r\n") .`

Wie Sie aus der Pipeline sehen, besteht der Decodierungsteil aus zwei Handlern. Die erste teilt und vereinigt die empfangenen Daten in eine einzelne Zeile und streift die Zeile, die von ihr endet. Der zweite konvertiert die einzelne Zeichenfolge in java.lang.String.

Auf der Codierungsseite gibt es nur einen Handler, der java.lang.String in ByteBuf konvertiert, und das ist alles, was es tut. Vielleicht ist es besser vorstellen ein Handler LineEncoder genannt, LineDecoder und LineCodec, dass die in der Regel erwartet Job macht: https://github.com/netty/netty/issues/1811

+1

Das ist eine wirklich alberne Antwort auf mein Problem, aber ironischerweise hat es funktioniert .... Wow, ich wusste nicht, dass es wählerisch bei dieser Information ist. – Maxs728

+0

Ich hätte das nicht erraten können. Seltsames Verhalten, gibt es einen Grund dafür? – Czechnology

+0

Die Antwort wurde aktualisiert, um die Fragen in den Kommentaren zu beantworten. – trustin

1

new String DO ("test"). Das wäre generischer. Beantworten Sie den letzten Teil Ihres Posts - Erstellen Sie ein Klassenobjekt mit all Ihren Informationen wie Logins, Spielerbewegungen usw. im Objekt und übergeben Sie es. Stellen Sie sicher, dass Ihre Klasse Serializable implementiert. es als String Passing ist ein schlechter Weg, es zu tun, da ich annehmen, dass es eine Art hardcoded.Client Code werden wird wie folgt aussehen wird:

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

Server-Code wird wie folgt aussehen:

ChannelPipeline p = ch.pipeline(); 

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

Server Handler wird:

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

Dies liefert keine Antwort auf die Frage. Um einen Autor zu kritisieren oder um Klärung zu bitten, hinterlasse einen Kommentar unter seinem Beitrag - du kannst deine eigenen Beiträge jederzeit kommentieren, und sobald du genügend [Reputation] (http://stackoverflow.com/help/whats-reputation) hast, wirst du das tun in der Lage sein [jeden Beitrag kommentieren] (http://stackoverflow.com/help/privileges/comment). – Achrome

+0

Ich benutze das und es funktioniert. Die Verwendung eines ObjectEncoder und ObjectDecoders passt eher zu seinem Usecase als zum String-Decoder. Das war Teil seiner Frage. Obwohl es eine akzeptierte Antwort auf sein ursprüngliches Problem gibt, habe ich einen ganz anderen Ansatz vorgeschlagen. – naves

+0

Wenn Sie dies verwenden und es funktioniert, können Sie ein Code-Snippet zur Veranschaulichung bereitstellen? Das aktuelle Format Ihrer Antwort hilft nicht wirklich. – Achrome

Verwandte Themen