Игры обычно имеют длинные соединения и пользовательские протоколы, и не используют HTTP -протоколы. Я не буду говорить о биографии, NIO, AIO и т. Д., Проверьте информацию самостоятельно.
Я использую Spring+Netty, чтобы настроить простой игровой сервер
Идеи: 1. Пользовательский протокол и пакет протоколов; 2.Spring+Netty Integration; 3. Обработка прилипания пакетов, механизм сердцебиения и т. Д.; 4. Распространение Request (в настоящее время я делаю режим Singleton)
Далее для тестирования, структура выглядит следующим образом
Во -первых, настроить заголовок пакета
Header.java
пакет com.test.netty.message; / ** * header.java * Направляющий заголовок протокола * @author janehuang * @version 1.0 */ public Class Header {private Byte Tag; /* Кодирование*/ частный байтовый кодирование; /* Шифрование*/ Частный байт шифровал; /*Другие поля*/ private byte extend1; /*Другое 2*/ Частный байт extend2; /*SessionId*/ private String SessionId; /*Длина пакета*/ private int длина = 1024; /*Команда*/ private int cammand; public header () {} public Header (String sessionId) {this.encode = 0; this.encrypt = 0; this.sessionId = sessionId; } Общественный заголовок (байтовый тег, байтовый кодирование, байтовая шифровая, байтовая шифровая, байтовая extend1, byte extend2, string sessionId, int length, int bullet) {this.tag = Tag; this.encode = encode; this.encrypt = incrypt; this.extend1 = extend1; this.extend2 = extend2; this.sessionId = sessionId; this.length = длина; this.cammand = cammand; } @Override public String toString () {return "Header [tag =" + tag + "encode =" + encode + ", incrypt =" + incrypt + ", extend1 =" + extend1 + ", extend2 =" + extend2 + ", sessionId =" + sessionId + ", length =" + length + ", cammand =" + "]"] "]"; ";"; } public byte getTag () {return Tag; } public void setatag (byte Tag) {this.tag = Tag; } public byte getEncode () {return encode; } public void setencode (byte encode) {this.encode = encode; } public byte getEncrypt () {return encrypt; } public void setEncrypt (byte encrypt) {this.encrypt = incrypt; } public byte getExtend1 () {return extend1; } public void setExtend1 (byte extend1) {this.extend1 = extend1; } public byte getExtend2 () {return extend2; } public void setexTend2 (byte extend2) {this.extend2 = extend2; } public String getSearsId () {return sessionId; } public void setSessionId (String sessionId) {this.SessionId = sessionId; } public int getLength () {return Length; } public void setlength (int length) {this.length = length; } public int getCammand () {return campmand; } public void setCammand (int campmand) {this.cammand = campmand; }} Я просто обрабатываю использование строки в Bytecode. Как правило, многие игры используют серии «Проблемы» для превращения в двоичный
Сообщение. Java
пакет com.test.netty.message; Импорт io.netty.buffer.bytebuf; Импорт io.netty.buffer.unpooled; импортировать java.io.bytearrayoutputstream; импортировать java.io.ioexception; импортировать java.io.unsupportedencodingexception; Import com.test.netty.decoder.messagedecoder; / ** * Сообщение частные строковые данные; Общественный заголовок Getheader () {return Header; } public void setheader (заголовок заголовка) {this.header = header; } public String getData () {return data; } public void setData (String Data) {this.Data = data; } public message (заголовок заголовка) {this.header = header; } public message (заголовок заголовка, строки данных) {this.header = header; this.data = data; } public byte [] tobyte () {bytearrayoutputstream out = new BytearrayOutputStream (); out.write (messagedecoder.package_tag); out.write (header.getencode ()); out.write (header.getencrypt ()); out.write (header.getextend1 ()); out.write (header.getextend2 ()); байт [] bb = новый байт [32]; byte [] bb2 = header.getSessionId (). getBytes (); for (int i = 0; i <bb2.length; i ++) {bb [i] = bb2 [i]; } try {out.write (bb); byte [] bbb = data.getbytes ("utf-8"); out.write (inttobytes2 (bbb.length)); out.write (inttobytes2 (header.getCammand ())); out.write (bbb); out.write ('/n'); } catch (unsupportedencodingexception e) {// todo автоматически сгенерированный блок e.printstacktrace (); } catch (ioException e) {// todo автоматически сгенерированный блок e.printstacktrace (); } return Out.tobyTearray (); } public static byte [] 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); вернуть Intbyte; } public static int bytestoint (byte [] src, int offset) {int value; value = (int) ((src [offset] & 0xff) | ((src [offset + 1] & 0xff) << 8) | ((src (offset + 2] & 0xff) << 16) | (src [offset + 3] & 0xff) << 24)); возвращаемое значение; } public static byte [] inttobytes2 (int value) {byte [] src = new Byte [4]; src [0] = (byte) ((значение >> 24) & 0xff); src [1] = (byte) ((значение >> 16) & 0xff); src [2] = (byte) ((значение >> 8) & 0xff); src [3] = (byte) (значение и 0xff); вернуть SRC; } public static void main (string [] args) {bytebuf heapbuffer = unpooled.buffer (8); System.out.println (Heapbuffer); BytearRayOutputStream OUT = New BytearRayOutputStream (); try {out.write (inttobytes2 (1)); } catch (ioException e) {// todo автоматически сгенерированный блок e.printstacktrace (); } byte [] data = out.tobytearray (); heapbuffer.writebytes (data); System.out.println (Heapbuffer); int a = heapbuffer.readint (); System.out.println (a); }} Декодер
MOSSAGEDECODER.JAVA
пакет com.test.netty.decoder; Импорт io.netty.buffer.bytebuf; Импорт io.netty.channel.channelhandlercontext; Импорт io.netty.handler.codec.bytetomessagedecoder; Импорт io.netty.handler.codec.corruptedFrameException; импортировать java.util.list; Import com.test.netty.message.header; Импорт com.test.netty.message.message; / *** headerdecoder.java** @author janehuang* @version 1.0*/ public class messagedecoder extends bytetomessagedecoder {/ ** Заголовок длины пакета **/ public static final int head_lenght = 45; / ** Заголовок флага **/ public Static Final Byte Package_tag = 0x01; @Override Protected void Декод (ChannelHandLercontext CTX, буфер bytebuf, список <object> out) Throws Exception {buffer.markreaderIndex (); if (buffer.ReadbableBytes () <Head_lenght) {бросить новый corruptedFrameException ("Проблема длины пакета"); } byte Tag = buffer.readbyte (); if (Tag! = package_tag) {бросить новый corruptedFrameException ("ошибка флага"); } byte encode = buffer.readbyte (); byte incrypt = buffer.readbyte (); byte extend1 = buffer.readbyte (); byte extend2 = buffer.readbyte (); byte sessionbyte [] = новый байт [32]; buffer.readbytes (sessionbyte); String sessionId = new String (SessionByte, "UTF-8"); int length = buffer.readint (); int cammand = buffer.readint (); Заголовок Header = новый заголовок (тег, кодирование, шифрование, extend1, extend2, sessionId, длина, камманд); byte [] data = new Byte [длина]; buffer.readbytes (data); Сообщение сообщения = новое сообщение (заголовок, новая строка (данные, "UTF-8")); out.add (сообщение); }} Энкодер
MessageEncoder.java
пакет com.test.netty.encoder; Import com.test.netty.decoder.messagedecoder; Import com.test.netty.message.header; Импорт com.test.netty.message.message; Импорт io.netty.buffer.bytebuf; Импорт io.netty.channel.channelhandlercontext; импорт io.netty.handler.codec.messagetobyteencoder; / ** * messageEncoder.java * * @author janehuang * @version 1.0 */ public class messagederer extends messagetobyteencoder <Сообщение> {@Override Protected void Encode (Channelhandlercontext Ctx, сообщение MSG, ByteBuf Out) throws exception {header header = msg.gethead ();); out.writebyte (messagedecoder.package_tag); out.writebyte (header.getencode ()); out.writebyte (header.getencrypt ()); out.writebyte (header.getextend1 ()); out.writebyte (header.getextend2 ()); out.writebytes (header.getSessionId (). GetBytes ()); out.writeint (header.getlength ()); out.writeint (header.getCammand ()); out.writebytes (msg.getdata (). getbytes ("utf-8")); }} сервер
Timeserver.java
пакет com.test.netty.server; Import org.springframework.stereotype.component; Импорт io.netty.bootstrap.serverbootstrap; Импорт io.netty.buffer.bytebuf; Импорт io.netty.buffer.unpooled; Импорт io.netty.channel.channelfuture; Импорт io.netty.channel.channelinitialize; Импорт io.netty.channel.channeloption; Импорт io.netty.channel.eventloopgroup; Импорт io.netty.channel.nio.nioeventloopgroup; Импорт io.netty.channel.socket.socketchannel; Импорт io.netty.channel.socket.nio.nioserversocketchannel; Импорт io.netty.handler.codec.linebasedFrameDecoder; Import com.test.netty.decoder.messagedecoder; Import com.test.netty.encoder.messageencoder; Импорт com.test.netty.handler.serverhandler; / ** * Chatserver.java * * @author janehuang * @version 1.0 */ @component public class timeserver {private int port = 88888; public void run () бросает прерванную экзенцию {eventloopgroup bossgroup = new nioeventloopgroup (); EventLoopGroup WorkerGroup = new nioeventloopgroup (); Bytebuf heapbuffer = unpooled.buffer (8); heapbuffer.writebytes ("/r" .getbytes ()); try {serverBootStrap b = new ServerBootStrap (); // (2) B.Group (BossGroup, WorkerGroup) .Channel (nioServerSocketchannel.class) // (3) .childHandler (New Channelinitializer <socketchannel> () {// (4) @Override public void initchannel (socketchannel ch) throus exception {ch.pipeline (). MessageEncoder ()). Addlast ("Декодер", новый MessagedeCoder ()). AddFirst (New LineBasedFrameDecoder (65535)). Addlast (new ServerHandler ()); // (6) Channelfuture F = B.Bind (порт) .sync (); // (7) f.channel (). CloseFuture (). Sync (); } наконец {korkergroup.shutdowngracebount (); bossgroup.shutdowngracebout (); }} public void start (int port) throws urruptEdException {this.port = port; this.run (); }} Процессор и распространять
ServerHandler.java
пакет com.test.netty.handler; Импорт io.netty.channel.ChannelHandlerAdapter; Импорт io.netty.channel.channelhandlercontext; Импорт com.test.netty.invote.actionmaputil; Import com.test.netty.message.header; Импорт com.test.netty.message.message; / ** * * * @author janehuang * */ public class serverhandler extends channelhandleradapter {@override public void wannelactaint (channelhandlercontext ctx) Throws {String content = "Я получил соединение"; Заголовок Header = новый заголовок ((байт) 0, (байт) 1, (байт) 1, (байт) 1, (байт) 0, "713F17CA614361FB257DC6741332CAF2", Content.getBytes ("UTF-8"). Длина, 1); Сообщение сообщения = новое сообщение (заголовок, контент); ctx.writeandflush (сообщение); } @Override public void exceptionCaught (ChannelHandlercontext ctx, бросаемая причина) {canes.printstacktrace (); ctx.close (); } @Override public void ChannelRead (ChannelHandLercOntext CTX, Object MSG) бросает исключение {сообщение m = (сообщение) msg; // (1)/* Распределение запросов*/ actionmaputil.invote (header.getCammand (), ctx, m); }} Категория инструмента распределения
Actionmaputil.java
пакет com.test.netty.invote; импортировать java.lang.reflect.method; импортировать java.util.hashmap; импортировать java.util.map; открытый класс ActionMaputil {частная статическая карта <integer, action> map = new Hashmap <Integer, action> (); public Static Object Invote (целочисленный ключ, объект ... args) бросает исключение {action action = map.get (key); if (action! = null) {method method = action.getMethod (); try {return method.invoke (action.getObject (), args); } catch (Exception e) {throw e; }} return null; } public static void put (целочисленный ключ, действие действие) {map.put (key, action); }} Объекты, созданные для распространения
Action.java
пакет com.test.netty.invote; импортировать java.lang.reflect.method; открытый класс Action {Private Method Method; частный объект объекта; публичный метод getMethod () {return Method; } public void setMethod (метод метода) {this.method = method; } public Object getObject () {return Object; } public void setObject (объект объекта) {this.object = object; }}Пользовательские аннотации, похожие на @controller в Springmvc
Nettycontroller.java
пакет com.test.netty.core; импортировать java.lang.annotation.documented; импортировать java.lang.annotation.elementtype; Импорт java.lang.annotation.retention; импортировать java.lang.annotation.retentionpolicy; импортировать java.lang.annotation.target; Import org.springframework.stereotype.component; @Retention (hestumentpolicy.runtime) @Target (elementType.type) @documented @component public @Interface nettyController {} @Reqestmapping в типе Spring MVC
Actionmap.java
пакет com.test.netty.core; импортировать java.lang.annotation.documented; импортировать java.lang.annotation.elementtype; Импорт java.lang.annotation.retention; импортировать java.lang.annotation.retentionpolicy; импортировать java.lang.annotation.target; @Retention (artencypolicy.runtime) @target (elementtype.method) @documented public @Interface actionMap {int key (); } Эти аннотации добавляются для хранения этих объектов в контейнере после пружинной инициализации бобов. Этот фасоль должен быть настроен весной. Весенний фасоль будет вызван после экземпляра.
Actionbeanpostprocessor.java
пакет com.test.netty.core; импортировать java.lang.reflect.method; Импорт org.springframework.beans.beansexception; Импорт org.springframework.beans.factory.config.beanpostprocessor; Импорт com.test.netty.invote.action; Импорт com.test.netty.invote.actionmaputil; открытый класс ActionBeanpostProcessor реализует BeanpostProcessor {public Object postprocessbeforeinialization (Object Bean, String Beanname) Throws Beansexception {return Bean; } открытый объект постпроцессафтеринициализация (объект Bean, String Beanname) Throws Beansexception {method [] method = bean.getClass (). getMethods (); для (метод метода: методы) {actionmap actionmap = method.getannotation (actionmap.class); if (actionmap! = null) {action action = new action (); action.setmethod (метод); action.setObject (bean); Actionmaputil.put (actionmap.key (), action); }} return Bean; }} Экземпляр контроллера
Usercontroller.java
пакет com.test.netty.controller; Импорт io.netty.channel.channelhandlercontext; Импорт org.springframework.beans.factory.annotation.autowired; импорт com.test.model.usermodel; Import com.test.netty.core.actionMap; Import com.test.netty.core.nettyController; Импорт com.test.netty.message.message; Импорт com.test.service.userservice; @Nettycontroller () public class userAction {@Autowired private userservice userservice; @ActionMap (key = 1) public String login (ChannelHandLercontext ct, сообщение сообщением) {usermodel usermodel = this.userservice.findbymasteruserid (1000001); System.out.println (string.format («Использование прозвища: %s; пароль %d; содержание передатчика %s», usermodel.getnickname (), usermodel.getid (), message.getdata ())); вернуть usermodel.getnickname (); }} Не забудьте добавить это в файл конфигурации ApplicationContext.xml
<bean/>
Тестовый код
Пакет -тест; Импорт org.springframework.context.applicationContext; Import org.springframework.context.support.classpathxmlapplicationContext; Импорт com.test.netty.server.timeserver; открытый тест класса {public static void main (string [] args) {ApplicationContext ac = new classpathxmlapplicationContext ("applicateContext.xml"); Timeserver Timeserver = ac.getbean (timeserver.class); try {timeserver.start (8888); } catch (прерванная экспрессия e) {// todo автоматически сгенерированный блок e.printstacktrace (); }}} Тестовый переключатель конец
Пакет -тест; импортировать java.io.ioexception; импортировать java.io.outputstream; импортировать java.net.socket; импортировать java.util.scanner; Import com.test.netty.message.header; Импорт com.test.netty.message.message; открытый класс clientTest {public static void main (string [] args) {try {// подключиться к сокету сервера = new Socket ("127.0.0.1", 8888); try {// dataOutputStream, который отправляет информацию на Server outputStream Out = socket.getOutputStream (); // Украсить стандартный входной поток, используемый для ввода из сканера консоли -сканера = новый сканер (System.in); while (true) {string send = scanner.nextline (); System.out.println ("client:" + send); byte [] by = send.getbytes ("utf-8"); Заголовок заголовка = новый заголовок ((байт) 1, (байт) 1, (байт) 1, (байт) 1, (байт) 1, (байт) 1, "713F17CA614361FB257DC6741332CAF2", by.Length, 1); Сообщение сообщения = новое сообщение (заголовок, отправить); out.write (message.tobyte ()); out.flush (); // Отправить информацию, полученную из консоли на сервер // out.writeutf ("client:" + send); // Читать информацию с сервера}} наконец {socket.close (); }} catch (ioException e) {e.printstacktrace (); }}}Результаты теста, ОК
Выше всего содержание этой статьи. Я надеюсь, что это будет полезно для каждого обучения, и я надеюсь, что все будут поддерживать Wulin.com больше.