Question

Dans le cadre de mon protocole, j'aimerais que le client envoie son numéro de version lorsqu'une nouvelle connexion est établie. J'aimerais que cela soit fait dans un gestionnaire séparé dans le pipeline, alors veuillez m'apporter car cela peut être une question assez basique, mais je ne sais pas comment le faire. L'autre chose est que j'aimerais alors pouvoir envoyer des allers-retours de Pojo à travers la connexion (pipeline). J'adorerais aussi ajouter un gestionnaire d'authentification. Quoi qu'il en soit, en ce moment, je reçois une sorte d'erreur et je suis presque sûr que c'est parce que la vérification de la version n'est pas correctement digérée à partir du pipeline.

Fondamentalement, le code que j'ai ci-dessous est configuré pour envoyer "Hello World" que le serveur imprime après la vérification de la version lorsque la connexion a été établie. Au moins en théorie, en réalité, cela ne fonctionne pas tout à fait;)

Actuellement, j'ai:

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
}

Donc, fondamentalement, ce que je veux, c'est que le numéro de version est passé et validé lorsque le canal est connecté dans le cadre du protocole de communication. Tout fait automatiquement dans les coulisses. De même, j'aimerais passer le mécanisme d'authentification de cette façon.

J'ai vu un code qui ressemblait un peu à ce que je voulais faire avec l'exemple de chat sécurisé, mais je ne pouvais pas vraiment le comprendre. Toute aide sur la façon de configurer ce code serait vraiment appréciée. Je sais que je pourrais tout faire dans un seul gestionnaire massif, mais c'est le but du pipeline, pour le diviser en unités qui ont du sens logique.

Était-ce utile?

La solution

J'ai trouvé la solution !!!

Il y avait un certain nombre de problèmes.

Sur VersionClientHandler, le nouveau code est:

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

Remarquez la dernière ligne, e.getChannel().write(version); à la place de Channels.write(ctx, e.getFuture(), versionBuffer); Je ne suis pas sûr du pourquoi. En fait, je suis sur le point de commencer à chercher pourquoi j'ai le code ChannelBuffers là-bas parce qu'il ne semble rien faire ...

Sur versionserverhandler.java j'ai maintenant:

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

Remarque que je ne lis plus le tampon, je fais juste e.getMessage() et coulé au type d'objet correct. Au-dessus de cela, j'ai ajouté ctx.getPipeline().remove(VersionServerHandler.class); qui est là pour retirer ce gestionnaire de tout traitement supplémentaire. Il n'est plus nécessaire après la connexion initiale. Merci à Dennis pour cette astuce.

Conclusion

Le reste est bien que je m'y attendais. La clé est que je ne comprenais pas correctement comment lire les tampons et passer les informations. Et les messages d'erreur et les exemples n'étaient pas tout à fait clairs. Dès que vous ajoutez les canaux Pojo de Netty à votre pipeline, vous devez commencer à traiter uniquement dans des objets, pour tous les gestionnaires. J'ai raté celui-là. Les concepts étaient corrects, c'est comme ça que j'ai essayé de lire les données des canaux qui étaient faux.

L'autre grande pointe, consistait à retirer les gestionnaires du pipeline si vous n'en avez pas besoin après la connexion initiale. Je suppose que la même chose sera vraie pour un gestionnaire d'authentification. Ce serait formidable d'avoir une confirmation ici, mais je devrai le comprendre plus tard.

Autres conseils

Vous n'avez pas mentionné l'erreur que vous voyez.

Dans tous les cas, je ne recommanderais pas d'utiliser un gestionnaire de canaux séparé pour effectuer une vérification de version. Principalement parce que la vérification de la version ne doit avoir besoin de se produire qu'une seule fois, lorsque la connexion est établie pour la première fois. De plus, parce que je pense que les gestionnaires de canaux sont mieux laissés aux prises avec des problèmes de couche de transport, par exemple, la conversion des octets en Pojos.

J'ai créé un exemple simple: https://github.com/boldt/netty-examples/

Il renvoie le numéro de version lorsqu'une nouvelle connexion est établie. Il se fait dans un gestionnaire séparé qui sera supprimé du pipeline une fois la version écrite sur la chaîne. Ensuite, c'est l'exemple d'écho du tutoriel Netty.

UN telnet localhost 1234 au serveur affiche immédiatement la version.

Comme ceci, vous pouvez ajouter un manteau d'authentification au pipeline derrière le manteau de version.

Je pense que ce que vous voulez faire peut être archivé facilement en ajoutant des gestionnaires personnalisés. Donc, pour la version, vous pouvez ajouter un gestionnaire qui remplacer ChannelConned (....) et y vérifier. Pour Auth, ajoutez un autre gestionnaire après la version Vérifiez qui remplace la méthode MessageRereved (....). Une fois l'authentification terminée, vous pouvez retirer le gestionnaire du pipeline et l'ajouter une fois que vous en avez besoin.

Le gestionnaire BusinessLogic doit s'asseoir en cours comme le dernier. Sachez simplement que l'un de vos gestionnaires fait une opération de blocage que vous devez penser à ajouter un exécution de l'exécution devant lui pour mKe sûre que le fil d'Ioworker sera bloqué et rendra donc le serveur netty non répondu.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top