Les jeux ont généralement de longues connexions et des protocoles personnalisés et n'utilisent pas de protocoles HTTP. Je ne parlerai pas de Bio, Nio, AIO, etc., vérifiez vous-même les informations.
J'utilise Spring + Netty pour configurer un serveur de jeu simple
Idées: 1. Protocole et protocole personnalisés; 2.Spring + Intégration Netty; 3. Half-Packet Sticking Traitement, Mécanisme de battement de cœur, etc.; 4. Distribution de la demande (actuellement, je fais du mode singleton)
Ensuite, c'est pour les tests, la structure est la suivante
Tout d'abord, personnalisez l'en-tête du package
En-tête.java
package com.test.netty.mesage; / ** * Header.java * En-tête de protocole personnalisé * @author JaneHuang * @version 1.0 * / en-tête de classe publique {Tag d'octet privé; / * Encodage * / Encode d'octet privé; / * Encryption * / Entrée d'octet privé; / * Autres champs * / octet privé Extend1; / * Autre 2 * / octet privé Extend2; / * SessionId * / private String SessionID; / * Longueur du package * / private int longueur = 1024; / * Commande * / private int Cammand; en-tête public () {} en-tête public (string sessionId) {this.encode = 0; this.encrypt = 0; this.SessionId = sessionId; } En-tête public (tag d'octet, encodage d'octets, octet crypt, octet crypt, octet extension1, octet extend2, string sessionId, int length, int bullet) {this.tag = tag; this.encode = encode; this.encrypt = crypt; this.Extend1 = extend1; this.Extend2 = extend2; this.SessionId = sessionId; this.length = longueur; this.cammand = cammand; } @Override public String toString () {return "En-tête [tag =" + tag + "Encode =" + Encode + ", Encrypt =" + Encrypt + ", Extend1 =" + Extend1 + ", Extend2 =" + Extend2 + ", sessiond =" + sessiond + ", longueur =" + longueur + ", camand =" + cammand + "]";; } octet public getTag () {return tag; } public void Settag (byte tag) {this.tag = tag; } public octet getEncode () {return Encoder; } public void setEncode (octet encode) {this.encode = encode; } octet public getEnCrypt () {return Encrypt; } public void setEnCrypt (octet Encrypt) {this.encrypt = Encrypt; } octet public getExtend1 () {return extend1; } public void sextend1 (byte prolond1) {this.extend1 = extend1; } octet public getExtend2 () {return extend2; } public void sextend2 (byte prolond2) {this.extend2 = extend2; } public String getSessionID () {return sessionId; } public void setSessionId (String SessionID) {this.SessionId = sessionId; } public int getLength () {return longueur; } public void setLength (int longueur) {this.length = longueur; } public int getCammand () {return Campmand; } public void setCammand (int campmand) {this.cammand = campmand; }} Je traite simplement l'utilisation de la chaîne en bytecode. Généralement, de nombreux jeux utilisent la série probuf pour se transformer en binaire
Message.java
package com.test.netty.mesage; import io.netty.buffer.bytebuf; import io.netty.buffer.unpooled; Importer java.io.ByteArrayOutputStream; Importer java.io.ioException; Importer java.io.UNSUPPORTEDENCODINGException; import com.test.netty.decoder.MessageDecoder; / ** * message.java * * @author JaneHuang * @version 1.0 * / Message de classe publique {En-tête privé En-tête; données de chaîne privées; En-tête public getheader () {en-tête de retour; } public void Setheader (en-tête d'en-tête) {this.header = en-tête; } public String getData () {return data; } public void setData (String data) {this.data = data; } message public (en-tête d'en-tête) {this.header = en-tête; } message public (en-tête d'en-tête, données de chaîne) {this.header = en-tête; this.data = data; } byte public [] tobyte () {bytearrayoutputStream out = new ByteArrayOutputStream (); out.write (MessageDecOder.Package_Tag); out.write (header.getEncode ()); out.write (header.getCrypt ()); out.write (header.getExtend1 ()); out.write (header.getExtend2 ()); octet [] bb = nouveau octet [32]; octet [] bb2 = en-tête.getSessionId (). GetBytes (); for (int i = 0; i <bb2.length; i ++) {bb [i] = bb2 [i]; } essayez {out.write (bb); octet [] bbb = data.getBytes ("utf-8"); out.write (intToBytes2 (bbb.length)); out.write (intToBytes2 (header.getCammand ())); out.write (BBB); out.write ('/ n'); } catch (UnportEnCoDingException e) {// Bloc de catch généré automatiquement de TODO E.PrintStackTrace (); } catch (ioException e) {// TODO Bloc de capture généré automatiquement e.printStackTrace (); } return out.toByTearray (); } public static octet [] intToByte (int newint) {byte [] intByte = new Byte [4]; intByte [3] = (byte) ((newint >> 24) & 0xff); intByte [2] = (byte) ((newint >> 16) & 0xff); intByte [1] = (byte) ((newint >> 8) & 0xff); intByte [0] = (byte) (newint & 0xff); retour intbyte; } public static int byTesToint (byte [] src, int offset) {int value; valeur = (int) ((src [offset] & 0xff) | ((src [offset + 1] & 0xff) << 8) | ((src [offset + 2] & 0xff) << 16) | ((src [offset + 3] & 0xff) << 24)); valeur de retour; } octet statique public [] InttoBytes2 (valeur int) {byte [] src = new byte [4]; src [0] = (byte) ((valeur >> 24) & 0xff); src [1] = (byte) ((valeur >> 16) & 0xff); src [2] = (byte) ((valeur >> 8) & 0xff); src [3] = (byte) (valeur & 0xff); retourner src; } public static void main (String [] args) {bytebuf heapbuffer = untooled.buffer (8); System.out.println (HeapBuffer); ByTearrayOutputStream out = new ByteArrayOutputStream (); essayez {out.write (intToBytes2 (1)); } catch (ioException e) {// TODO Bloc de capture généré automatiquement e.printStackTrace (); } byte [] data = out.toByTearray (); HeapBuffer.WriteBytes (données); System.out.println (HeapBuffer); int a = heapbuffer.readInt (); System.out.println (a); }} Décodeur
MessageDeccoder.java
package com.test.netty.decoder; import io.netty.buffer.bytebuf; import io.netty.channel.channelHandlerContext; import io.netty.handler.codec.bytetoMessageDecoder; import io.netty.handler.codec.corruptedFrameException; Importer java.util.list; import com.test.netty.message.header; import com.test.netty.message.message; / ** * headerdecoder.java * * @author JaneHuang * @version 1.0 * / public class MessageDecoder étend BytetoMessageDecoder {/ ** En-tête de longueur de package ** / public static final int head_lenght = 45; / ** En-tête de drapeau ** / public static final byte package_tag = 0x01; @Override Protected void Decode (ChannelHandlerContext CTX, ByteBuf Buffer, List <Bject> Out) lève l'exception {tampon.markreaderIndex (); if (buffer.readableBytes () <head_lenght) {lancez new CorruptedFrameException ("Package Longuet Issue"); } byte tag = buffer.readByte (); if (tag! = package_tag) {throw new CorruptedFrameException ("Flag Error"); } octet encode = buffer.readByte (); BYTE ENCRYPT = BUFFER.READBYTE (); octet extend1 = buffer.readByte (); octet extend2 = buffer.readByte (); Byte SessionByte [] = Nouveau octet [32]; Buffer.ReadBytes (SessionByte); String sessionID = new String (sessionByte, "UTF-8"); int length = buffer.readInt (); int Cammand = buffer.readInt (); En-tête d'en-tête = nouvel en-tête (balise, encoder, encrypt, extension1, extension2, sessiond, longueur, cammand); octet [] data = nouveau octet [longueur]; buffer.readbytes (données); Message Message = nouveau message (en-tête, nouvelle chaîne (données, "UTF-8")); out.add (message); }} Encodeur
MessageEncoder.java
package com.test.netty.encoder; import com.test.netty.decoder.MessageDecoder; import com.test.netty.message.header; import com.test.netty.message.message; import io.netty.buffer.bytebuf; import io.netty.channel.channelHandlerContext; import io.netty.handler.codec.MessageToByteencoder; / ** * MessageEncoder.java * * @author JaneHuang * @version 1.0 * / public class MessageEncoder étend MessagetoByteencoder <Message> {@Override Protected vid Encode (ChannersHandlerContext CTX, message msg, bytebuf out) lance exception {henter en tête = msg.GETHEADER ();); out.writeByte (MessageDecOder.Package_Tag); out.writeByte (header.getEncode ()); out.writeByte (header.getCrypt ()); out.writeByte (header.getExtend1 ()); out.writeByte (header.getExtend2 ()); out.writeBytes (header.getSessionId (). GetBytes ()); out.writeInt (en-tête.GetLength ()); out.writeInt (header.getCammand ()); out.writeBytes (msg.getData (). GetBytes ("UTF-8")); }} serveur
Timesserver.java
package com.test.netty.server; import org.springframework.sterereotype.Component; import io.netty.bootstrap.serverbootstrap; import io.netty.buffer.bytebuf; import io.netty.buffer.unpooled; import io.netty.channel.chanfuture; import io.netty.channel.channelinitializer; import io.netty.channel.channeloption; import io.netty.channel.eventloopgroup; import io.netty.channel.nio.nioeventloopgroup; import io.netty.channel.socket.socketchannel; import io.netty.channel.socket.nio.nioserversocketchannel; Importer io.netty.handler.codec.lineBasedFrameDecoder; import com.test.netty.decoder.MessageDecoder; import com.test.netty.encoder.messageencoder; import com.test.netty.handler.serverHandler; / ** * ChatServer.java * * @author JaneHuang * @version 1.0 * / @Component public class timeserver {private int port = 88888; public void run () lève InterruptedException {EventLoopGroup BossGroup = new NioEventLoopGroup (); EventLoopGroup WorkerGroup = new NioEventLoopGroup (); Bytebuf heapbuffer = nonoled.buffer (8); heapbuffer.writeBytes ("/ r" .getBytes ()); essayez {serverbootstrap b = new serverbootstrap (); // (2) B.Group (BossGroup, WorkerGroup) .Channel (Nioserversocketchannel.class) // (3) .ChildHandler (New ChannelInitializer <Socketchannel> () {// (4) @Override public Void Initchannel (Socketchannel Ch) lance Exception {ch.pipeline (). MessageEncoder ()). AddLast ("Decoder", new MessagedCoder ()). // (6) Channelfuture f = B.Bind (port) .Sync (); // (7) F.Channel (). CloseFuture (). Sync (); } enfin {workerGroup.shutdowngracely (); bossgroup.shutdowngracely (); }} public void start (int port) lance InterruptedException {this.port = port; this.run (); }} Processeur et distribuer
Server-handler.java
package com.test.netty.handler; import io.netty.channel.channelhandleradapter; import io.netty.channel.channelHandlerContext; import com.test.netty.invote.actionMaputil; import com.test.netty.message.header; import com.test.netty.message.message; / ** * * @Author JaneHuang * * / public class ServerHandler étend ChannelHandleradapter {@Override public void ChannelActive (ChannelHandlerContext CTX) lève une exception {String Content = "J'ai reçu la connexion"; En-tête d'en-tête = nouvel en-tête ((octet) 0, (octet) 1, (octet) 1, (octet) 1, (octet) 0, "713f17ca614361fb257dc6741332caf2", contenu.getbytes ("utf-8"). Longueur, 1); Message message = nouveau message (en-tête, contenu); ctx.writeAndflush (message); } @Override public void exceptioncaught (canalshandlerContext ctx, cause throwable) {cause.printStackTrace (); ctx.close (); } @Override public void ChannelRead (ChannelHandlerContext ctx, objet msg) lève l'exception {message m = (message) msg; // (1) / * Distribution de la demande * / ActionMaputil.invote (header.getCammand (), ctx, m); }} Catégorie d'outils de distribution
Actionmaputil.java
package com.test.netty.invote; import java.lang.reflect.method; import java.util.hashmap; importation java.util.map; Classe publique RECLAGEMAPUTIL {Private Static Map <Integer, Action> map = new HashMap <Integer, Action> (); Public Static Object Invote (clé entière, objet ... args) lance l'exception {action action = map.get (key); if (action! = null) {méthode méthode = action.getMethod (); essayez {return method.invoke (action.getObject (), args); } catch (exception e) {throw e; }} return null; } public static void put (clé entière, action d'action) {map.put (key, action); }} Objets créés pour la distribution
Action.java
package com.test.netty.invote; import java.lang.reflect.method; Action de classe publique {Méthode privée Méthode; objet privé objet; Méthode publique getMethod () {Retour Méthode; } public void setMethod (méthode méthode) {this.method = méthode; } public objet getObject () {return objet; } public void setObject (objet objet) {this.object = objet; }}Annotations personnalisées, similaires à @Controller dans Springmvc
NetyController.java
package com.test.netty.core; import java.lang.annotation.documented; import java.lang.annotation.elementType; import java.lang.annotation.retention; Importer java.lang.annotation.retentionPolicy; import java.lang.annotation.target; import org.springframework.sterereotype.Component; @Retention (RetentionPolicy.Runtime) @target (elementType.Type) @Documented @Component public @Interface NetTyController {} @Reqestmapping dans le type de printemps MVC
Actionmap.java
package com.test.netty.core; import java.lang.annotation.documented; import java.lang.annotation.elementType; import java.lang.annotation.retention; Importer java.lang.annotation.retentionPolicy; import java.lang.annotation.target; @Retention (RetentionPolicy.Runtime) @target (elementType.Method) @Documented Public @Interface ActionMap {int key (); } Ces annotations sont ajoutées pour stocker ces objets dans le conteneur après les haricots d'initialisation de ressort. Ce haricot doit être configuré au printemps. Le haricot de printemps sera appelé après l'instanciation.
ActionBeanPostprocessor.java
package com.test.netty.core; import java.lang.reflect.method; import org.springframework.beans.beanSexception; import org.springframework.beans.factory.config.beanPostProcessor; import com.test.netty.invote.action; import com.test.netty.invote.actionMaputil; La classe publique ActionBeanPostProcessor implémente BeanPostProcessor {Object Public PostProcessBeforeInitialization (Object Bean, String Beanname) lève BeanSexception {return bean; } Objet public PostProcessAfterinitialization (Object Bean, String Beanname) lève BeanSexception {Method [] Methods = Bean.getClass (). getMethods (); pour (méthode méthode: méthodes) {ActionMap ActionMap = méthode.getAnnotation (actionmap.class); if (actionmap! = null) {action action = new Action (); action.setMethod (méthode); action.setObject (bean); Actionmaputil.put (actionmap.key (), action); }} return bean; }} Instance de contrôleur
UserController.java
package com.test.netty.Controller; import io.netty.channel.channelHandlerContext; import org.springframework.beans.factory.annotation.Autowired; import com.test.model.usermodel; import com.test.netty.core.actionmap; import com.test.netty.core.nettyController; import com.test.netty.message.message; import com.test.service.userservice; @NetTyController () classe publique UserAction {@Autowired Private UserService UserService; @ActionMap (key = 1) Public String Login (ChannelHandlerContext CT, message Message) {UserModel UserModel = this.UserService.FindByMasterUserrid (1000001); System.out.println (String.Format ("Utilisation de surnom:% s; mot de passe% D return userModel.getNickName (); }} N'oubliez pas d'ajouter ceci au fichier de configuration applicationContext.xml
<Bean />
Code de test
test de package; import org.springframework.context.ApplicationContext; import org.springframework.context.support.classPathxmlApplicationContext; import com.test.netty.server.timeserver; public class test {public static void main (string [] args) {applicationContext ac = new classPathxmlApplicationContext ("applicationContext.xml"); TimesServer Timesserver = ac.getBean (Timesserver.class); essayez {timeServer.Start (8888); } Catch (InterruptedException e) {// TODO Block de catch généré automatiquement e.printStackTrace (); }}} Extrémité du commutateur de test
test de package; Importer java.io.ioException; import java.io.outputStream; import java.net.socket; import java.util.scanner; import com.test.netty.message.header; import com.test.netty.message.message; classe publique ClientTest {public static void main (String [] args) {try {// Connexion au socket serveur socket = new socket ("127.0.0.1", 8888); essayez {// dataOutputStream qui envoie des informations au serveur OutputStream out = socket.getOutputStream (); // Décorez le flux d'entrée standard, utilisé pour saisir à partir du scanner de console = nouveau scanner (System.in); while (true) {String Send = Scanner.NextLine (); System.out.println ("Client:" + Send); octet [] par = send.getBytes ("utf-8"); En-tête d'en-tête = nouvel en-tête ((octet) 1, (octet) 1, (octet) 1, (octet) 1, (octet) 1, (octet) 1, "713f17ca614361fb257dc6741332caf2", par.length, 1); Message Message = nouveau message (en-tête, envoyé); out.write (message.tobyte ()); out.flush (); // Envoyez les informations obtenues à partir de la console au serveur // out.writeUtf ("Client:" + Send); // Lire les informations du serveur}} enfin {socket.close (); }} catch (ioException e) {e.printStackTrace (); }}}Résultats des tests, ok
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.