ゲームは通常、長い接続とカスタムプロトコルを持ち、HTTPプロトコルを使用しません。 Bio、Nio、AIOなどについては、自分で情報を確認しません。
Spring+Nettyを使用してシンプルなゲームサーバーを設定します
アイデア:1。カスタムプロトコルとプロトコルパッケージ。 2.Spring+Netty Integration; 3.ハーフパケットスティック処理、ハートビートメカニズムなど。 4.レクエスト分布(現在、私はシングルトンモードをやっています)
次はテスト用です。構造は次のとおりです
まず、パッケージヘッダーをカスタマイズします
header.java
パッケージcom.test.netty.message; / ** * header.java *カスタムプロトコルヘッダー * @author janehuang * @version 1.0 */ public class header {private byteタグ; /*エンコード*/プライベートバイトエンコード。 /*暗号化*/プライベートバイト暗号化。 /*その他のフィールド*/プライベートバイトextend1; /*その他2*/プライベートバイトextend2; /*sessionId*/ private string sessionId; /*パッケージの長さ*/ private int length = 1024; /*command*/ private int cammand; public header(){} public header(string sessionid){this.encode = 0; this.encrypt = 0; this.sessionId = sessionId; } public header(byteタグ、バイトエンコード、バイト暗号化、バイト暗号化、バイトextend1、byte endoct2、string sessionid、int length、int bullet){this.tag = tag; this.encode = encode; this.encrypt = encrypt; this.extend1 = extend1; this.extend2 = extend2; this.sessionId = sessionId; this.length = length; this.cammand = cammand; } @Override public String toString(){return "header [tag =" + tag + "encode =" + encode + "、encrypt =" + encrypt + "、extend1 =" + extend1 + "、extend2 =" + extend2 + "、sessionid =" + sessionid + "、length =" + " } public byte gettag(){return tag; } public void setag(byteタグ){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 ancrypt){this.encrypt = encrypt; } public byte getextEnd1(){return endoct1; } public void setextEnd1(byte endoct1){this.extend1 = extend1; } public byte getextEnd2(){return endoct2; } public void setextEnd2(byte endoct2){this.extend2 = extend2; } public string getSessionId(){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に処理するだけです。一般的に、多くのゲームは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.messageCoderをインポートします。 / ** * message.java * * @author janehuang * @version 1.0 */ public class message {private header header;プライベート文字列データ。パブリックヘッダーgetheader(){return header; } public void setheader(ヘッダーヘッダー){this.header = header; } public string getData(){return data; } public void setData(string data){this.data = data; } public Message(Header Header){this.header = header; } publicメッセージ(ヘッダーヘッダー、文字列データ){this.header = header; this.data = data; } public byte [] tobyte(){bytearrayoutputStream out = new bytearrayoutputStream(); out.write(mesagedecoder.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(); 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 auto-enerated catch block e.printstacktrace(); } catch(ioException e){// todo auto-fenated catch block e.printstacktrace(); } return.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)((value >> 24)&0xff); src [1] =(byte)((value >> 16)&0xff); src [2] =(byte)((value >> 8)&0xff); src [3] =(byte)(value&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 auto-fenated catch block e.printstacktrace(); } byte [] data = out.tobytearray(); heapbuffer.writebytes(data); system.out.println(heapbuffer); int a = heapbuffer.readint(); System.out.println(a); }}デコーダ
mesagedecoder.java
パッケージcom.test.netty.decoder; io.netty.buffer.bytebufをインポートします。 io.netty.channel.channelhandlercontextをインポートします。 io.netty.handler.codec.bytetomessageCoderをインポートします。 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 mesagedeCoderはbytetomessagedecoder {/ **パッケージ長ヘッダー**/ public static final int head_lenght = 45; / **フラグヘッダー**/ public static final byte packag_tag = 0x01; @Override Protected void decode(ChannelHandlerContext CTX、bytebufバッファー、list <Object> out)スロー{buffer.markreaderindex(); if(buffer.readablebytes()<head_lenght){throw new corroodedFrameException( "Package Length Issue"); } byte tag = buffer.readbyte(); if(tag!= package_tag){throw new corroodedframeexception( "flag error"); } byte encode = buffer.readbyte(); Byte encrypt = buffer.readbyte(); byte endex1 = buffer.readbyte(); byte endex2 = buffer.readbyte(); BYTE SESSIONBYTE [] = new Byte [32]; buffer.readbytes(sessionbyte); string sessionid = new String(sessionbyte、 "utf-8"); int length = buffer.readint(); int cammand = buffer.readint(); Header Header = new Header(タグ、エンコード、暗号化、extend1、extend2、sessionId、length、cammand); byte [] data = new byte [length]; buffer.readbytes(data);メッセージメッセージ= newメッセージ(Header、new String(data、 "utf-8")); out.add(メッセージ); }}エンコーダー
MessageEncoder.java
パッケージcom.test.netty.encoder; com.test.netty.decoder.messageCoderをインポートします。 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 <sessage> {@Overrideプロテクションボイドエンコード(ChannelHandlercontext CTX、Message MSG、bytebuf out)を拡張します。 out.writebyte(mesagedecoder.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")); }}サーバ
TimesServer.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.messageCoderをインポートします。 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()throws arturtedexception {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 inityannel(socketchannel ch)Throws Exception {ch.pipeline()。 messageencoder())。addlast( "decoder"、new MessageCoder())。 //(6)ChannelFelfuture f = b.bind(port).sync(); //(7)f.channel()。closefuture()。sync(); }最後に{workergroup.shutdowngracefuly(); BOSSGROUP.SHUTDOWNGRACELY(); }} public void start(int port)throws arturtedexception {this.port = port; this.run(); }}プロセッサと配布
ServerHandler.java
パッケージcom.test.netty.handler; io.netty.channel.channelhandleradapterをインポートします。 io.netty.channel.channelhandlercontextをインポートします。 com.test.netty.invote.actionmaputilをインポートします。 com.test.netty.message.headerをインポートします。 com.test.netty.message.messageをインポートします。 / ** * * @author janehuang * */ public class serverhandler拡張チャンネルハンドラーダプター{@override public void channelactive(channelhandlercontext ctx)スロー{文字列content = "接続を受信した"; Header Header = new Header((byte)0、(byte)1、(byte)1、(byte)1、(byte)0、 "713f17ca614361fb257dc674132caf2"、content.getbytes( "utf-8")。メッセージメッセージ= newメッセージ(Header、content); ctx.writeandflush(メッセージ); } @Override public void exceptionCaught(ChannelHandlerContext CTX、Throwable cause){cause.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.reflt.methodをインポートします。 java.util.hashmapをインポートします。 java.util.mapをインポートします。 Public Class ActionMaputil {private static Map <integer、action> map = new Hashmap <integer、action>(); public static object invote(integer key、object ... args)スロー例外{action action = map.get(key); if(action!= null){method method = action.getmethod(); try {return method.invoke(action.getobject()、args); } catch(例外e){スローe; }} nullを返します。 } public static void put(integer key、action action){map.put(key、action); }}配布用に作成されたオブジェクト
action.java
パッケージcom.test.netty.invote; java.lang.reflt.methodをインポートします。パブリッククラスアクション{プライベートメソッドメソッド;プライベートオブジェクトオブジェクト。パブリックメソッドgetMethod(){return method; } public void setMethod(メソッドメソッド){this.method = method; } public object getobject(){return object; } public void setObject(object object){this.object = object; }}springmvcの@controllerに似たカスタムアノテーション
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をインポートします。 org.springframework.stereotype.componentをインポートします。 @retention(retentionPolicy.runtime)@target(elementType.type)@documented @component public @interface nettycontroller {}タイプスプリングMVCの@ReQESTMAPPING
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(RetentionPolicy.Runtime)@Target(elementType.Method)@Documented Public @Interface ActionMap {int key(); }これらの注釈は、春の初期化した豆の後にこれらのオブジェクトを容器に保存するために追加されます。この豆は春に構成する必要があります。スプリングビーンは、インスタンス化後に呼び出されます。
ActionBeanPostProcessor.java
パッケージcom.test.netty.core; java.lang.reflt.methodをインポートします。 Import org.springframework.beans.beansexception; Import org.springframework.beans.factory.config.beanpostprocessor; com.test.netty.invote.actionをインポートします。 com.test.netty.invote.actionmaputilをインポートします。 Public Class ActionBeanPostProcessorはBeanPostProcessorを実装しています{Public Object PostProcessBeforeInitialization(Object Bean、String BeanName)Throws BeanSexception {return Bean; } public Object postprocessafterinitialization(object bean、string beanname)throws beansexception {methods [] methods = bean.getclass()。getMethods(); for(method method:method){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をインポートします。 Import 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()public class useraction {@autowired private userservice userservice; @actionmap(key = 1)public string login(channelhandlercontext ct、message message){usermodel usermodel = this.userservice.findbymasteruserid(1000001); System.out.println(string.format( "nickname:%s; password%d; transmitter content%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 class test {public static void main(string [] args){applicationContext AC = new ClassPathxMLApplicationContext( "ApplicationContext.xml"); TimeServer TimesServer = AC.GetBean(TimesServer.Class); {TimesServer.start(8888); } catch(arturnedexception e){// todo auto-fenated catch block e.printstacktrace(); }}}テストスイッチの終了
パッケージテスト; java.io.ioexceptionをインポートします。 java.io.outputStreamをインポートします。 java.net.socketをインポートします。 Java.util.scannerをインポートします。 com.test.netty.message.headerをインポートします。 com.test.netty.message.messageをインポートします。 public class clientTest {public static void main(string [] args){try {//サーバーソケット= new Socket( "127.0.0.1"、8888); try {// server outputStream out = socket.getOutputStream(); //コンソールスキャナースキャナーから入力するために使用される標準の入力ストリームを飾ります= new Scanner(system.in); while(true){string send = scanner.nextline(); System.out.println( "client:" + send); byte [] by = send.getBytes( "utf-8");ヘッダーヘッダー= new Header((byte)1、(byte)1、(byte)1、(byte)1、(byte)1、(byte)1、 "713f17ca614361fb257dc6741332caf2"、by.length、1);メッセージメッセージ= newメッセージ(Header、send); out.write(message.tobyte()); out.flush(); //コンソールから取得した情報をサーバーに送信する// out.writeutf( "client:" + send); //サーバーから情報を読む}} fullly {socket.close(); }} catch(ioexception e){e.printstacktrace(); }}}テスト結果、OK
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。