Domanda

Come parte del mio protocollo, vorrei che il client inviasse il suo numero di versione quando viene stabilita una nuova connessione. Mi piacerebbe che questo fosse fatto in un gestore separato nella pipeline, quindi per favore abbi pazienza perché questa potrebbe essere una domanda abbastanza semplice ma non sono sicuro di come farlo. L'altra cosa è che mi piacerebbe poter quindi inviare i POJO avanti e indietro attraverso la connessione (pipeline). Inoltre mi piacerebbe aggiungere un gestore di autenticazione. Ad ogni modo, in questo momento ricevo una sorta di errore e sono abbastanza sicuro che sia perché il controllo della versione non viene digerito correttamente dalla pipeline.

Fondamentalmente il codice che ho sotto è impostato per inviare "Hello World" che il server stampa dopo che la versione è stata controllata quando la connessione è stata stabilita. Almeno in teoria, in realtà non funziona del tutto;)

Attualmente ho:

Client.java

public static void main(String[] args)
{
    ...

    // Set up the pipeline factory.
    bootstrap.setPipelineFactory(new ChannelPipelineFactory() 
    {
        @Override
        public ChannelPipeline getPipeline() throws Exception 
        {
            return Channels.pipeline(
                    new ObjectEncoder(),
                    new ObjectDecoder(),
                    new VersionClientHandler(),
                    new BusinessLogicClientHandler());
        }
    });     

    ...

    // The idea is that it will all be request and response. Much like http but with pojo's. 
    ChannelFuture lastWriteFuture = channel.write("Hello world".getBytes());

    if (lastWriteFuture != null) 
    {
        System.out.println("waiting for message to be sent");
           lastWriteFuture.awaitUninterruptibly();
    }

    ...
}

VersionClientHandler.java

public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
{
    ChannelBuffer versionBuffer = ChannelBuffers.buffer(VERSION_STRING_LENGTH);
    versionBuffer.writeBytes("v123.45a".getBytes());
    // If I understand correctly, the next line says use the rest of the stream to do what you need to the next Handler in the pipeline?
    Channels.write(ctx, e.getFuture(), versionBuffer);  
}

BusinessLogicClientHandler.java

Not really doing anything at this point. Should it?

Server.java

public static void main(String[] args)
{
    ...

    public ChannelPipeline getPipeline() throws Exception 
    {
        return Channels.pipeline(
                new ObjectEncoder(),
                new ObjectDecoder(),
                new VersionServerHandler(),
                new BusinessLogicServerHandler());
    }

    ...
}

VersionServerHandler.java

public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) 
{
    ChannelBuffer versionBuffer = ChannelBuffers.buffer(VERSION_NUMBER_MAX_SIZE);
    System.out.println("isReadable - messageReceived: " + versionBuffer.readable()); // returns false???
    // Basically I want to read it and confirm the client and server versions match.
    // And if the match fails either send a message or throw an exception
    // How do I also pass on the stream to the next Handler? 
}

BusinessLogicServerHandler.java

public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) 
{
    e.getMessage();
    byte[] message = (byte[])e.getMessage(); // "Hello World" in byte[] from Client.java
}

Quindi, in pratica, quello che voglio è che il numero di versione venga passato e convalidato quando il canale è connesso come parte del protocollo di comunicazione. Tutto fatto automaticamente dietro le quinte. Allo stesso modo mi piacerebbe far passare il meccanismo di autenticazione in questo modo.

Ho visto un codice che somigliava in qualche modo a quello che volevo fare con l'esempio di Secure Chat, ma non sono riuscito a capirlo. Qualsiasi aiuto su come impostare questo codice sarebbe davvero apprezzato. So che potrei fare tutto in un unico enorme gestore, ma questo è il punto della pipeline, suddividerlo in unità che abbiano un senso logico.

È stato utile?

Soluzione

Ho trovato la soluzione !!!

Si sono verificati diversi problemi.

Su VersionClientHandler, il nuovo codice è:

public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
{
    String verison = "v123.45a";

    ChannelBuffer versionBuffer = ChannelBuffers.buffer(VERSION_STRING_LENGTH);
    versionBuffer.writeBytes(version.getBytes());
    e.getChannel().write(version);
}

Nota l'ultima riga, e.getChannel().write(version); invece di Channels.write(ctx, e.getFuture(), versionBuffer);, non sono sicuro del perché. In effetti, sto per iniziare a cercare il motivo per cui ho il codice ChannelBuffers perché sembra che non faccia nulla ...

Su VersionServerHandler.java ora ho:

public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) 
{
    String versionCheck = (String)e.getMessage();
    System.out.println("VersionServerHandler - " + versionCheck);
    ctx.getPipeline().remove(VersionServerHandler.class);
}

Nota che non leggo più il buffer, faccio solo e.getMessage() e cast sul tipo corretto di oggetto. Sopra questo ho aggiunto ctx.getPipeline().remove(VersionServerHandler.class); che è lì per rimuovere quel gestore da qualsiasi ulteriore elaborazione. Non è più necessario dopo la connessione iniziale. Grazie a Dennis per il suggerimento.

<”Conclusione

Il resto è come mi aspettavo. la chiave è che non stavo capendo correttamente come leggere i buffer e passare le informazioni in giro. E i messaggi di errore e gli esempi non erano del tutto chiari. Non appena aggiungi i canali POJO da Netty alla tua pipeline, devi iniziare a trattare solo oggetti, per tutti i gestori. Mi è mancato quello. I concetti erano giusti, è proprio come ho cercato di leggere i dati dai canali che era sbagliato.

L'altro grande suggerimento è stato rimuovere i gestori dalla pipeline se non ne hai bisogno dopo la connessione iniziale. Presumo che lo stesso sarà vero per un gestore di autenticazione. Sarebbe bello avere una conferma qui, ma dovrò scoprirla più tardi.

Altri suggerimenti

Non hai menzionato quale fosse l'errore che stai vedendo.

In ogni caso, non consiglierei di utilizzare un gestore di canale separato per eseguire un controllo della versione.Principalmente perché il controllo della versione dovrebbe essere necessario solo una volta, quando la connessione viene stabilita per la prima volta.Anche perché penso che è meglio lasciare che i gestori di canale si occupino delle preoccupazioni del livello di trasporto, ad es.convertire i byte in pojo.

Penso che quello che vuoi fare possa essere facilmente archiviato aggiungendo alcuni gestori personalizzati.Quindi per il controllo della versione potresti aggiungere un gestore che sovrascriva channelConnected (....) e fai il controllo lì.Per auth basta aggiungere un altro gestore dopo il controllo della versione che sovrascrive il metodo messageRecieved (....).Dopo che l'autenticazione è completa, puoi rimuovere il gestore dalla pipeline e aggiungerlo di nuovo quando ne avrai bisogno di nuovo.

Il gestore di BusinessLogic dovrebbe essere l'ultimo nella pipeline.Tieni solo presente che uno qualsiasi dei tuoi gestori esegue alcune operazioni di blocco, dovresti pensare di aggiungere un ExecutionHandler davanti ad esso per assicurarti che il thread ioworker non venga bloccato e quindi rendere il server netty non responsabile.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top