2012-12-17 20 views
10

Questo è in realtà il mio primo post qui e ho cercato di capirlo per qualche tempo, ma alla fine sto chiamando la bandiera e cercherò di ottenere un aiuto su questo argomento.Messaggio Netty Client to Server

Quindi ho un client e un server che è stato modellato dopo il client/server echo e il client/server di chat sicuro. Non sono interessato alla parte SSL della chat e uso l'eco solo per assicurarmi di ottenere risposte da e verso il client/server. Aggiungerò tutto il codice pertinente in fondo a questo post. Il problema che sto ottenendo al momento è che posso inviare un messaggio dal server al client al momento della connessione del client, ma non sono in grado di inviare un messaggio dal client al server sul server che invia al client il messaggio iniziale. Il messaggio inviato dal server è:

Welcome to the server! 

Il messaggio da parte del cliente è

test 

io deve sapere che ho ricevuto il messaggio dal client causa che dovrebbe risuonare di nuovo

[You] test 

So che il server vede il client e mi dà aggiornamenti di stato ma non posso inviare un messaggio al server per qualche motivo. Ora per una domanda in cima a questo ... Per caso sto usando un StringDecoder e StringEncoder come Decodificatore ed Encoder ... Se stai facendo un gioco (che è quello che sto facendo) e tu avrà cose come accessi, movimenti di giocatori, aggiornamenti mondiali, ecc ... sta mandando Strings il modo migliore per farlo? So di vedere molto con i flussi di byte e nella mia classe di programmazione sono passato a manipolare i flussi di byte, ma non sono ancora al 100% a loro agio con loro. Se i flussi di byte sono il modo migliore/migliore per farlo, allora qualcuno può spiegare in dettaglio come funziona a manipolare un flusso di byte per essere in grado di gestire diversi elementi.

Come detto prima che questo è l'inizio di tutto nel 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()); 
} 
} 

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

} 

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

Ancora una volta tutti Apprezzo tutto l'aiuto che potete darli sulla comprensione questo.

+0

Qualsiasi codice lato server? – Peter

+0

Sfortunatamente non sapevo se qualcuno avrebbe voluto, ma dovrei anche aggiungere che posso Telnet localhost 45000 al mio server e fa come previsto lì ..... Sto modificando il post originale da aggiungere al server codice. – Maxs728

+0

Chiunque può aiutarmi con questo problema? – Maxs728

risposta

4

Hai dimenticato di aggiungere \r\n a "test". Dovrebbe essere: channel.write("test\r\n") .`

Come si vede dalla pipeline, la parte di decodifica è composta da due gestori. Il primo divide e unisce i dati ricevuti in una singola riga di stringa e taglia la linea che termina da essa. Il secondo converte la singola riga di stringa in java.lang.String.

Sul lato di codifica, c'è un solo gestore, che converte uno java.lang.String in ByteBuf, e questo è tutto ciò che fa. Forse è meglio introdurre un gestore chiamato LineEncoder, LineDecoder, e LineCodec che fa il lavoro di solito previsto: https://github.com/netty/netty/issues/1811

+1

Questa è una risposta davvero stupida al mio problema, ma ironicamente ha funzionato .... Wow, non sapevo che fosse pignolo riguardo a quell'informazione. – Maxs728

+0

Non avrei potuto immaginarlo. Strano comportamento, c'è una ragione per questo? – Czechnology

+0

Aggiornamento della risposta per rispondere alle domande nei commenti. – trustin

1

DO new String ("test"). Sarebbe più generico. Rispondi a quest'ultima parte del tuo post- Crea un oggetto di classe con tutte le tue informazioni come accessi, movimenti dei giocatori ecc. Nell'oggetto e passalo. Assicurati che la tua classe implementa Serializable. Passando come stringa è un brutto modo di farlo in quanto presumo che diventerà una sorta di codice di hardcoded.Client sarà simile a questa:

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

codice Server sarà simile a questa:

ChannelPipeline p = ch.pipeline(); 

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

Server Handler sarà:

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

Questo non fornisce una risposta alla domanda. Per criticare o richiedere chiarimenti da un autore, lascia un commento sotto il loro post - puoi sempre commentare i tuoi post, e una volta che hai [reputazione] sufficiente (http://stackoverflow.com/help/whats-reputation) essere in grado di [commentare qualsiasi post] (http://stackoverflow.com/help/privileges/comment). – Achrome

+0

Sto usando questo e funziona. Usando ObjectEncoder e ObjectDecoder si adatta meglio al suo Usecase piuttosto che al Decoder String. Era parte della sua domanda. Anche se c'è una risposta accettata al suo problema originale, ho suggerito un approccio completamente diverso. – naves

+0

Se stai usando questo e funziona, puoi pubblicare uno snippet di codice da illustrare? Il formato attuale della tua risposta non è di grande aiuto. – Achrome