Netty + ProtoBuffer: quelques messages de communication pour une connexion

Lors de la lecture du didacticiel Netty, j’ai trouvé une description simple de la façon d’intégrer les tampons de protocole Netty et Google . J’ai commencé à étudier son exemple (car il n’y a plus d’informations dans la documentation) et j’ai écrit une application simple, telle que l’exemple d’application locale. Mais cet exemple utilise une initialisation statique dans PipeFactory Class, par exemple:

import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.handler.codec.protobuf.ProtobufDecoder; import org.jboss.netty.handler.codec.protobuf.ProtobufEncoder; import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; import static org.jboss.netty.channel.Channels.pipeline; /** * @author sergiizagriichuk */ class ProtoCommunicationClientPipeFactory implements ChannelPipelineFactory { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline p = pipeline(); p.addLast("frameDecoder", new ProtobufVarint32FrameDecoder()); p.addLast("protobufDecoder", new ProtobufDecoder(Communication.DataMessage.getDefaultInstance())); p.addLast("frameEncoder", new ProtobufVarint32LengthFieldPrepender()); p.addLast("protobufEncoder", new ProtobufEncoder()); p.addLast("handler", new ProtoCommunicationClientHandler()); return p; } } 

(Veuillez regarder la ligne p.addLast("protobufDecoder", new ProtobufDecoder(Communication.DataMessage.getDefaultInstance())); ) et une seule fabrique peut être créée (si je comprends bien) pour la classe ClientBootstrap , je veux dire bootstrap.setPipelineFactory() méthode. Donc, dans cette situation, je peux utiliser UN message pour envoyer au serveur et UN message pour recevoir du serveur et c’est mauvais pour moi, et je pense pas seulement pour moi 🙁 Comment puis-je utiliser des messages différents de et vers pour une seule connexion ? Peut-être que je peux créer quelques protobufDecoder comme ceci

 p.addLast("protobufDecoder", new ProtobufDecoder(Communication.DataMessage.getDefaultInstance())); p.addLast("protobufDecoder", new ProtobufDecoder(Communication.TestMessage.getDefaultInstance())); p.addLast("protobufDecoder", new ProtobufDecoder(Communication.SrcMessage.getDefaultInstance())); 

ou d’autres techniques? Merci beaucoup.

J’ai trouvé le fil de l’auteur de Netty dans les groupes de Google et j’ai compris que je devais changer d’architecture ou écrire mon propre décodeur comme je l’ai écrit ci-dessus. Alors, commencez à penser de quelle manière ce sera facile et meilleur.

Si vous souhaitez malgré tout écrire vos propres codecs, vous pouvez envisager de mettre en œuvre l’interface Externalizable pour des objects de données personnalisés.

  • Sérialisable nécessite peu d’effort, mais moins performant (tout sérialiser).
  • Protobuf est un bon compromis entre effort et performance (nécessite une maintenance .proto)
  • Externalisable est un effort important, mais les meilleures performances (codecs minimaux personnalisés)

Si vous savez déjà que votre projet devra évoluer comme une chèvre de montagne, vous devrez peut-être suivre une route difficile. Protobuf n’est pas une solution miracle.

Théoriquement, cela peut être fait en modifiant le pipeline de chaque message entrant en fonction du message entrant. Jetez un coup d’œil à l’exemple de l’ unification des ports à Netty.

La séquence serait:
1) Dans le décodeur de trame ou un autre “DecoderMappingDecoder”, vous vérifiez le type de message du message entrant
2) Modifiez le pipeline de manière dynamic, comme indiqué dans l’exemple.

Mais pourquoi ne pas utiliser différentes connexions et suivre cette séquence:
1) Ajoutez d’autres décodeurs dans le pipeline en fonction du message entrant une seule fois.
2) Ajoutez la même instance de gestionnaire de canal en amont que le dernier gestionnaire du pipeline. Ainsi, tous les messages sont routés vers la même instance, ce qui revient presque à avoir une seule connexion.

le problème est qu’il n’ya aucun moyen de distinguer deux messages protobuf différents au format binary. Mais il existe un moyen de le résoudre dans le fichier protobuf:

 message AnyMessage { message DataMessage { [...] } optional DataMessage dataMessage = 1; message TestMessage { [...] } optional TestMessage testMessage = 2; message SrcMessage { [...] } optional SrcMessage srcMessage = 3; } 

Les champs facultatifs non définis ne génèrent pas de surcharge. De plus, vous pouvez append un Enum, mais ce n’est qu’un bonus.

Le problème n’est pas tout à fait une limitation Netty ou une limitation codeur / décodeur. Le problème est que les tampons de protocole Google offrent simplement un moyen de sérialiser / désérialiser des objects, mais ne fournissent pas de protocole. Ils ont une sorte d’implémentation RPC dans le cadre de la dissortingbution standard, mais si vous essayez d’implémenter leur protocole RPC, vous vous retrouverez avec 3 couches d’indirection. Ce que j’ai fait dans l’un des projets, c’était de définir un message qui est essentiellement une union de messages. Ce message contient un champ Type et un autre le message réel. Vous aurez toujours 2 couches indirection, mais pas 3. Ainsi, l’exemple de Netty fonctionnera pour vous, mais comme il a été mentionné dans un précédent post, vous devez append plus de logique dans le gestionnaire de logique métier.

Vous pouvez utiliser le tunneling de message pour envoyer différents types de messages sous forme de charge utile dans un seul message. J’espère que cela pourra aider

Après de longues recherches et des souffrances … j’ai eu l’idée d’utiliser la composition de messages dans un message enveloppant. Dans ce message, j’utilise oneof pour limiter le nombre d’objects autorisés à un seul. Commander l’exemple:

 message OneMessage { MessageType messageType = 1; oneof messageBody { Event event = 2; Request request = 3; Response response = 4; } ssortingng messageCode = 5; //unique message code int64 timestamp = 6; //server time }