عادة ما يكون للألعاب اتصالات طويلة وبروتوكولات مخصصة ، ولا تستخدم بروتوكولات HTTP. لن أتحدث عن Bio و Nio و AIO وما إلى ذلك ، تحقق من المعلومات بنفسك.
أنا أستخدم Spring+Netty لإعداد خادم لعبة بسيط
الأفكار: 1. بروتوكول مخصص وبروتوكول. 2.SPRENG+Netty Integration ؛ 3. HALF-Packet معالجة نصي ، آلية نبضات القلب ، إلخ ؛ 4. توزيع التوزيع (حاليًا ، أقوم بوضع Singleton)
التالي هو للاختبار ، الهيكل كما يلي
أولاً ، قم بتخصيص رأس الحزمة
header.java
حزمة com.test.netty.message ؛ / ** * header.java * رأس بروتوكول مخصص * Author janehuang * version 1.0 */ header class public {private byte tag ؛ /* الترميز*/ خاص بايت تشفير ؛ /* التشفير*/ بايت الخاص تشفير ؛ /*الحقول الأخرى*/ private byte تمتد 1 ؛ /*other 2*/ private byte Extend2 ؛ /*SessionId*/ private String SessionId ؛ /*طول الحزمة*/ طول الباحث الخاص = 1024 ؛ /*command*/ private int cammand ؛ header header () {} header public (String SessionId) {this.encode = 0 ؛ this.encrypt = 0 ؛ this.sessionId = SessionId ؛ } الرأس العام (علامة البايت ، تشفير البايت ، بايت تشفير ، بايت تشفير ، بايت تمدد 1 ، بايت تمدد 2 ، سلسلة SessionId ، طول int ، int bullet) {this.tag = tag ؛ this.encode = encode ؛ this.encrypt = encrypt ؛ this.extend1 = extend1 ؛ this.extend2 = تمديد 2 ؛ this.sessionId = SessionId ؛ this.length = الطول ؛ this.cammand = cammand ؛ } Override public string toString () {return "header [tag =" + tag + "encode =" + encode + "، encrypt =" + encrypt + "، extend1 =" + exted1 + "، extend2 =" + extend2 + "، sessionid =" + sessionid + "، length =" length + "، cammand =" cammand + "] ؛ } البايت العام getTag () {return tag ؛ } public void settag (tag byte) {this.tag = tag ؛ } public byte getencode () {return encode ؛ } public void setencode (byte encode) {this.encode = encode ؛ } البايت العام getencrypt () {return encrypt ؛ } public void setencrypt (byte encrypt) {this.encrypt = encrypt ؛ } 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 ؛ } السلسلة العامة getSessionId () {return SessionId ؛ } public void setSessionId (String SessionId) {this.sessionId = SessionId ؛ } public int getLength () {length length ؛ } public void setLength (int int) {this.length = length ؛ } public int getCammand () {return campmand ؛ } public void setCammand (int campmand) {this.cammand = campmand ؛ }} أنا ببساطة معالجة استخدام السلسلة إلى bytecode. بشكل عام ، تستخدم العديد من الألعاب سلسلة probuf لتحويلها إلى ثنائي
message.java
حزمة com.test.netty.message ؛ استيراد io.netty.buffer.bytebuf ؛ استيراد io.netty.buffer.unpooled ؛ استيراد java.io.bytearrayoutputstream ؛ استيراد java.io.ioException ؛ استيراد java.io.unsupportedencodingException ؛ استيراد com.test.netty.decoder.MessagedEcoder ؛ / ** * message.java * * Author Janehuang * @Version 1.0 */ Message Public Class {Private Header ؛ بيانات السلسلة الخاصة ؛ الرأس العام getheader () {return header ؛ } public void setheader (header header) {this.header = header ؛ } السلسلة العامة getData () {return data ؛ } public void setData (string data) {this.data = data ؛ } الرسالة العامة (رأس الرأس) {this.header = header ؛ } رسالة عامة (رأس رأس ، بيانات سلسلة) {this.header = header ؛ this.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 ()) ؛ Byte [] BB = New Byte [32] ؛ byte [] bb2 = header.getSessionId (). getBytes () ؛ لـ (int i = 0 ؛ i <bb2.length ؛ i ++) {bb [i] = bb2 [i] ؛ } جرب {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 catch catch e.printstacktrace () ؛ } catch (ioException e) {// todo acto catch block e.printstacktrace () ؛ } return out.tobytearray () ؛ } بايت ثابت عام [] 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. } static int bytestoint (byte [] src ، int indess) {int value ؛ value = (int) ((src [offset] & 0xff) | ((src [offset + 1] & 0xff) << 8) | ((src [offset + 2] & 0xff) << 16) | ((src [offset + 3] & 0xff) << 24)) ؛ قيمة الإرجاع } البايت الثابت العام [] inttobytes2 (int value) {byte [] src = new byte [4] ؛ src [0] = (byte) ((value >> 24) & 0xff) ؛ src [1] = (byte) ((value >> 16) & 0xff) ؛ src [2] = (byte) ((value >> 8) & 0xff) ؛ src [3] = (byte) (value & 0xff) ؛ إرجاع SRC ؛ } main static void main (string [] args) {bytebuf heapbuffer = unpooled.buffer (8) ؛ system.out.println (heapbuffer) ؛ bytearrayoutputstream out = new bytearrayoutputstream () ؛ حاول {out.write (inttobytes2 (1)) ؛ } catch (ioException e) {// todo acto catch block e.printstacktrace () ؛ } byte [] data = out.tobytearray () ؛ heapbuffer.writeBytes (البيانات) ؛ system.out.println (heapbuffer) ؛ int a = heapbuffer.readint () ؛ system.out.println (a) ؛ }} فك التشفير
messagedecoder.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 ؛ استيراد com.test.netty.message.header ؛ استيراد com.test.netty.message.message ؛ / *** HeaderDecoder.java** Author Janehuang* Version 1.0*/ Public Class MessagedEcoder يمتد BytetomessagedEcoder {/ ** حزمة طول الحزمة **/ public static Final int head_lenght = 45 ؛ / ** رأس العلامة **/ public static byte byte package_tag = 0x01 ؛ Override Decode Void Decode (ChannelHandLerContext CTX ، Bytebuf Buffer ، List <Object> out) يلقي الاستثناء {buffer.markReaderIndex () ؛ if (buffer.ReadableBytes () <head_lenght) {رمي جديد تالف frameException ("مشكلة طول الحزمة") ؛ } tag byte = buffer.readbyte () ؛ if (tag! = package_tag) {رمي جديد توسل frameException ("خطأ العلم") ؛ } byte encode = buffer.readbyte () ؛ byte encrypt = buffer.readbyte () ؛ Byte Extend1 = Buffer.ReadByte () ؛ Byte Extend2 = Buffer.ReadByte () ؛ Byte SessionByte [] = New Byte [32] ؛ Buffer.ReadBytes (SessionByte) ؛ سلسلة SessionId = سلسلة جديدة (SessionByte ، "UTF-8") ؛ طول int = buffer.readint () ؛ int cammand = buffer.readint () ؛ رأس رأس = رأس جديد (علامة ، تشفير ، تشفير ، تمديد 1 ، تمديد 2 ، جلسة ، طول ، cammand) ؛ Byte [] data = new byte [length] ؛ Buffer.ReadBytes (البيانات) ؛ رسالة رسالة = رسالة جديدة (رأس ، سلسلة جديدة (بيانات ، "UTF-8")) ؛ out.add (رسالة) ؛ }} تشفير
MessageenCoder.java
حزمة com.test.netty.encoder ؛ استيراد com.test.netty.decoder.MessagedEcoder ؛ استيراد 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 messageencoder يمتد messageTobyTeenCoder <message> {Override void Encode (msg.getheader () ؛ 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 ؛ استيراد org.springframework.stereotype.component ؛ استيراد io.netty.bootstrap.serverbootstrap ؛ استيراد io.netty.buffer.bytebuf ؛ استيراد io.netty.buffer.unpooled ؛ استيراد io.netty.channel.channelfuture ؛ استيراد io.netty.channel.channelinitializer ؛ استيراد 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 ؛ استيراد com.test.netty.decoder.MessagedEcoder ؛ استيراد com.test.netty.encoder.messageencoder ؛ استيراد com.test.netty.handler.serverhandler ؛ / ** * chatserver.java * * author janehuang * version 1.0 */ @component public classerver {private int port = 88888 ؛ public void run () remrows interruptedException {eventLoopGroup bossgroup = nioeventloopgroup () ؛ EventLoopGroup WorkerGroup = nioeventloopgroup () جديد ؛ bytebuf heapbuffer = unpooled.buffer (8) ؛ heapbuffer.writeBytes ("/r" .getBytes ()) ؛ حاول {serverBootStrap b = new serverbootstrap () ؛ // (2) B.Group (Bossgroup ، WorkerGroup) .Channel (nioserversocketchannel.class) // (3) .ChildHandler (new ChannelInitializer <OcketchAnl> () {// (4) Override public void initchannel (socketchannel ch) {ch.pipeline () MessageenCoder ()) // (6) Channelfuture f = b.bind (port) .sync () ؛ // (7) f.Channel (). closefuture (). sync () ؛ } أخيرًا {workergroup.shutdowngracely () ؛ bossgroup.shutdownlyly () ؛ }} public void start (int port) يلقي InterruptedException {this.port = port ؛ this.run () ؛ }} المعالج وتوزيع
ServerHandler.java
حزمة com.test.netty.handler ؛ استيراد io.netty.channel.ChannelHandlerAdAdapter ؛ استيراد io.netty.channel.channelhandlercontext ؛ استيراد com.test.netty.invote.actionmaputil ؛ استيراد com.test.netty.message.header ؛ استيراد com.test.netty.message.message ؛ / ** * * * Author Janehuang * */ Public Class ServerHandler يمتد قناة HandlerDerAdapter {Override Public Void Channelive (ChannelHandlerContext CTX) يلقي استثناء {string content = "لقد تلقيت الاتصال" ؛ رأس رأس = رأس جديد ((بايت) 0 ، (بايت) 1 ، (بايت) 1 ، (بايت) 1 ، (بايت) 0 ، "713F17CA614361FB257DC6741332CAF2" ، content.getbytes ("UTF-8"). الطول ، 1) ؛ رسالة رسالة = رسالة جديدة (رأس ، محتوى) ؛ ctx.writeandflush (message) ؛ } Override public void stisplycaught (ChannelHandLerContext CTX ، cause reflable) {cause.printStackTrace () ؛ ctx.close () ؛ } Override public void ChannelRead (ChannelHandLerContext CTX ، Object MSG) يرمي الاستثناء {message m = (message) msg ؛ // (1)/* request distribution*/ 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> () ؛ invote الكائن الثابت العام (مفتاح Integer ، كائن ... args) يلقي الاستثناء {Action Action = map.get (key) ؛ if (Action! = null) {method method = action.getMethod () ؛ حاول {return method.invoke (Action.getObject () ، args) ؛ } catch (استثناء e) {throw e ؛ }} الإرجاع null ؛ } pub static void pub (integer Key ، Action Action) {map.put (key ، action) ؛ }} الكائنات التي تم إنشاؤها للتوزيع
Action.java
حزمة com.test.netty.invote ؛ استيراد java.lang.reflect.method ؛ الطبقة العامة الإجراء {طريقة الطريقة الخاصة ؛ كائن خاص ؛ الطريقة العامة getMethod () {return method ؛ } public void setMethod (method method) {this.method = method ؛ } الكائن العام getObject () {return Object ؛ } public void setObject (Object) {this.object = object ؛ }}التعليقات التوضيحية المخصصة ، على غرار controller في springMVC
NetTyController.java
حزمة com.test.netty.core ؛ استيراد java.lang.annotation.documented ؛ استيراد java.lang.annotation.elementType ؛ استيراد java.lang.annotation.Reentering ؛ استيراد java.lang.annotation.RetentionPolicy ؛ استيراد java.lang.annotation.target ؛ استيراد org.springframework.stereotype.component ؛ repinention (attreentionpolicy.runtime) target (elementType.type) documented @component public interface nettyController {} reqestmapping في نوع الربيع MVC
ActionMap.Java
حزمة com.test.netty.core ؛ استيراد java.lang.annotation.documented ؛ استيراد java.lang.annotation.elementType ؛ استيراد java.lang.annotation.Reentering ؛ استيراد java.lang.annotation.RetentionPolicy ؛ استيراد java.lang.annotation.target ؛ repinention (attreentionpolicy.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 {الكائن العام postprocessbeforeinitialization (كائن الفول ، سلسلة beanname) يلقي beansexception {return Bean ؛ } الكائنات العامة postprocessafterinitialization (كائن فول ، سلسلة beanname) يلقي beansexception {method [] methods = bean.getclass (). getMethods () ؛ لـ (الطريقة الطريقة: الطرق) {ActionMap ActionMap = method.getAnnotation (ActionMap.class) ؛ if (ActionMap! = null) {Action Action = new Action () ؛ Action.setMethod (method) ؛ Action.setObject (Bean) ؛ ActionMaputil.put (ActionMap.Key () ، Action) ؛ }} إرجاع الفول ؛ }} مثيل وحدة التحكم
USERCONTROLLER.JAVA
حزمة com.test.netty.controller ؛ استيراد io.netty.channel.channelhandlercontext ؛ استيراد org.springframework.beans.factory.annotation.autowired ؛ استيراد com.test.model.usermodel ؛ استيراد com.test.netty.core.actionmap ؛ استيراد com.test.netty.core.nettycontroller ؛ استيراد com.test.netty.message.message ؛ استيراد com.test.service.userservice ؛ @nettycontroller () الفئة العامة userAction {autowired private userservice userservice ؛ @actionmap (key = 1) تسجيل الدخول إلى السلسلة العامة (channelhandlercontext ct ، رسالة رسالة) {usermodel usermodel = this.userservice.findbymasteruserid (1000001) ؛ System.out.println (string.format ("استخدام اللقب: ٪ s ؛ password ٪ d ؛ محتوى الإرسال ٪ s" ، usermodel.getnickname () ، usermodel.getid () ، message.getData ())) ؛ إرجاع usermodel.getNickName () ؛ }} تذكر أن تضيف هذا إلى ملف تكوين ApplicationContext.xml
<bean/>
رمز الاختبار
اختبار الحزمة استيراد org.springframework.context.applicationContext ؛ استيراد org.springframework.context.support.classpathxmlapplicationContext ؛ استيراد com.test.netty.server.timeserver ؛ اختبار الفئة العامة {public static void main (string [] args) {applicationContext ac = new ClassPathxMlapplicationContext ("ApplicationContext.xml") ؛ TimeServer timeserver = ac.getBean (timeServer.class) ؛ حاول {timeServer.start (8888) ؛ } catch (interruptedException e) {// todo catch catch e.printstacktrace () ؛ }}} نهاية التبديل نهاية
اختبار الحزمة استيراد java.io.ioException ؛ استيراد java.io.outputStream ؛ استيراد java.net.socket ؛ استيراد java.util.scanner ؛ استيراد com.test.netty.message.header ؛ استيراد com.test.netty.message.message ؛ ClientTest Public ClientTest {public static void main (string [] args) {try {// connect بمقبس Server Socket = New Socket ("127.0.0.1" ، 8888) ؛ جرب {// dataOutputStream الذي يرسل المعلومات إلى الخادم OutputStream out = socket.getOutputStream () ؛ // تزيين دفق الإدخال القياسي ، المستخدم للإدخال من ماسح الضوئي الماسح الضوئي = System.in) ؛ بينما (صحيح) {string send = scanner.nextLine () ؛ System.out.println ("العميل:" + إرسال) ؛ byte [] by = send.getBytes ("utf-8") ؛ رأس رأس = رأس جديد ((بايت) 1 ، (بايت) 1 ، (بايت) 1 ، (بايت) 1 ، (بايت) 1 ، (بايت) 1 ، "713F17CA614361FB257DC67413332CAF2" ، بواسطة. رسالة رسالة = رسالة جديدة (رأس ، إرسال) ؛ out.write (message.tobyte ()) ؛ out.flush () ؛ // إرسال المعلومات التي تم الحصول عليها من وحدة التحكم إلى الخادم // Out.writeUtf ("العميل:" + إرسال) ؛ // اقرأ المعلومات من الخادم}} أخيرًا {socket.close () ؛ }} catch (ioException e) {E.PrintStackTrace () ؛ }}}نتائج الاختبار ، حسنًا
ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.