一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|JavaScript|易語言|

服務器之家 - 編程語言 - JAVA教程 - spring+netty服務器搭建的方法

spring+netty服務器搭建的方法

2021-03-29 10:09病毒先生 JAVA教程

本篇文章主要介紹了spring+netty服務器搭建的方法,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

游戲一般是長連接,自定義協議,不用http協議,bio,nio,aio這些我就不說了,自己查資料

我現在用spring+netty搭起簡單的游戲服

思路:1自定義協議和協議包;2spring+netty整合;3半包粘包處理,心跳機制等;4請求分發(目前自己搞的都是單例模式)
下個是測試用的,結構如下

spring+netty服務器搭建的方法

首先自定義包頭

header.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package com.test.netty.message;   
/**
 * header.java
 * 自定義協議包頭
 * @author janehuang
 * @version 1.0
 */
public class header { 
  private byte tag; 
 /* 編碼*/ 
  private byte encode; 
  /*加密*/ 
  private byte encrypt; 
  /*其他字段*/ 
  private byte extend1; 
  /*其他2*/ 
  private byte extend2; 
  /*會話id*/ 
  private string sessionid; 
  /*包的長度*/ 
  private int length = 1024; 
  /*命令*/
  private int cammand; 
  
  public header() { 
  
  
  
  public header(string sessionid) { 
    this.encode = 0
    this.encrypt = 0
    this.sessionid = sessionid; 
  
  
  public header(byte tag, byte encode, byte encrypt, byte extend1, byte extend2, string sessionid, int length, int cammand) { 
    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=" + length + ",cammand="
        + cammand + "]"
  
  
  public byte gettag() { 
    return tag; 
  
  
  public void settag(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 = 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; 
  
  
  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 cammand; 
  
  
  public void setcammand(int cammand) { 
    this.cammand = cammand; 
  
}

包體,我簡單處理用字符串轉字節碼,一般好多游戲用probuf系列化成二進制

message.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package com.test.netty.message;   
import io.netty.buffer.bytebuf; 
import io.netty.buffer.unpooled;  
import java.io.bytearrayoutputstream; 
import java.io.ioexception; 
import java.io.unsupportedencodingexception;  
import com.test.netty.decoder.messagedecoder;  
/**
 * message.java
 
 * @author janehuang
 * @version 1.0
 */
public class message { 
  
  private header header; 
  
  private string data; 
  
  public header getheader() { 
    return header; 
  
  
  public void setheader(header header) { 
    this.header = header; 
  
  
  public string getdata() { 
    return data; 
  
  
  public void setdata(string data) { 
    this.data = data; 
  
  
  public message(header header) { 
    this.header = header; 
  
  
  public message(header header, string data) { 
    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()); 
    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-generated catch block 
      e.printstacktrace(); 
    } catch (ioexception e) { 
      // todo auto-generated catch block 
      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); 
    return 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)); 
    return value; 
  
  
  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); 
    return 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-generated catch block 
      e.printstacktrace(); 
    
    byte[] data = out.tobytearray(); 
    heapbuffer.writebytes(data); 
    system.out.println(heapbuffer); 
    int a = heapbuffer.readint(); 
    system.out.println(a); 
  }   
}

解碼器

messagedecoder.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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; 
import 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 extends bytetomessagedecoder {
  /**包長度志頭**/
  public static final int head_lenght = 45;
  /**標志頭**/
  public static final byte package_tag = 0x01;
  @override
  protected void decode(channelhandlercontext ctx, bytebuf buffer, list<object> out) throws exception {
    buffer.markreaderindex();
    if (buffer.readablebytes() < head_lenght) {
      throw new corruptedframeexception("包長度問題");
    }
    byte tag = buffer.readbyte();
    if (tag != package_tag) {
      throw new corruptedframeexception("標志錯誤");
    }
    byte encode = buffer.readbyte();
    byte encrypt = buffer.readbyte();
    byte extend1 = buffer.readbyte();
    byte extend2 = 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(tag,encode, encrypt, extend1, extend2, sessionid, length, cammand);
    byte[] data=new byte[length];
    buffer.readbytes(data);
    message message = new message(header,new string(data,"utf-8"));
    out.add(message);
  }
}

編碼器

messageencoder.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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 extends messagetobyteencoder<message> { 
  @override
  protected void encode(channelhandlercontext ctx, message msg, bytebuf out) throws exception {
      header header = 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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.test.netty.server;
import org.springframework.stereotype.component;
import io.netty.bootstrap.serverbootstrap;
import io.netty.buffer.bytebuf;
import io.netty.buffer.unpooled;
import io.netty.channel.channelfuture;
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;
import 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() throws interruptedexception {
    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) throws exception {
                  ch.pipeline().addlast("encoder", new messageencoder()).addlast("decoder", new messagedecoder()).addfirst(new linebasedframedecoder(65535))
                      .addlast(new serverhandler());
                }
              }).option(channeloption.so_backlog, 1024) // (5)
          .childoption(channeloption.so_keepalive, true); // (6)
      channelfuture f = b.bind(port).sync(); // (7)
      f.channel().closefuture().sync();
    } finally {
      workergroup.shutdowngracefully();
      bossgroup.shutdowngracefully();
    }
  }
   
  public void start(int port) throws interruptedexception{
   this.port=port;
   this.run();
  
}

處理器并分發

serverhandler.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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 extends channelhandleradapter {
 
  @override
  public void channelactive(channelhandlercontext ctx) throws exception {
    string content="我收到連接";
    header header=new header((byte)0, (byte)1, (byte)1, (byte)1, (byte)0, "713f17ca614361fb257dc6741332caf2",content.getbytes("utf-8").length, 1);
    message message=new message(header,content);
    ctx.writeandflush(message);     
  }
 
  @override
  public void exceptioncaught(channelhandlercontext ctx, throwable cause) {
    cause.printstacktrace();
    ctx.close();
  }
 
  @override
  public void channelread(channelhandlercontext ctx, object msg) throws exception {
     message m = (message) msg; // (1)
      
    /* 請求分發*/
    actionmaputil.invote(header.getcammand(),ctx, m);
  }     
}

分發工具類

actionmaputil.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.test.netty.invote;
import java.lang.reflect.method;
import java.util.hashmap;
import java.util.map;
public class actionmaputil {
  private static map<integer, action> map = new hashmap<integer, action>(); 
  public static object invote(integer key, object... args) throws exception {
    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(integer key, action action) {
    map.put(key, action);
  
}

為分發創建的對象

action.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.test.netty.invote; 
import java.lang.reflect.method; 
public class action {   
  private method method;
  private object object; 
  public method getmethod() {
    return method;
  }
 
  public void setmethod(method method) {
    this.method = method;
  }
 
  public object getobject() {
    return object;
  }
 
  public void setobject(object object) {
    this.object = object;
  }
}

自定義注解,類似springmvc 里面的@controller

nettycontroller.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.test.netty.core; 
import java.lang.annotation.documented;
import java.lang.annotation.elementtype;
import java.lang.annotation.retention;
import java.lang.annotation.retentionpolicy;
import java.lang.annotation.target; 
import org.springframework.stereotype.component; 
@retention(retentionpolicy.runtime)
@target(elementtype.type)
@documented
@component
public @interface nettycontroller {
}

類型spring mvc里面的@reqestmapping

actionmap.java

?
1
2
3
4
5
6
7
8
9
10
11
12
package com.test.netty.core;
import java.lang.annotation.documented;
import java.lang.annotation.elementtype;
import java.lang.annotation.retention;
import java.lang.annotation.retentionpolicy;
import java.lang.annotation.target; 
@retention(retentionpolicy.runtime)
@target(elementtype.method)
@documented
public @interface actionmap {
    int key();    
}

加了這些注解是為了spring初始化bean后把這些對象存到容器,此bean需要在spring配置,spring bean 實例化后會調用

actionbeanpostprocessor.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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;
public class actionbeanpostprocessor implements beanpostprocessor {
  public object postprocessbeforeinitialization(object bean, string beanname) throws beansexception {
    return bean;
  }
 
  public object postprocessafterinitialization(object bean, string beanname) throws beansexception {
    method[] methods=bean.getclass().getmethods();
    for (method method : methods) {
      actionmap actionmap=method.getannotation(actionmap.class);
      if(actionmap!=null){
        action action=new action();
        action.setmethod(method);
        action.setobject(bean);
        actionmaputil.put(actionmap.key(), action);
      }
    }
    return bean;
  }
}

controller實例

usercontroller.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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()
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("用戶昵稱:%s;密碼%d;傳人內容%s", usermodel.getnickname(),usermodel.getid(),message.getdata()));
    return usermodel.getnickname();
  
}

applicationcontext.xml配置文件記得加入這個

?
1
<bean class="com.test.netty.core.actionbeanpostprocessor"/>

測試代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package test;
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"); 
     timeserver timeserver= ac.getbean(timeserver.class);
     try {
      timeserver.start(8888);
    } catch (interruptedexception e) {
      // todo auto-generated catch block
      e.printstacktrace();
    }
  }
}

測試開關端

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package test; 
import 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; 
public class clienttest {
   public static void main(string[] args) {
    try {
      // 連接到服務器
      socket socket = new socket("127.0.0.1", 8888); 
      try {
        // 向服務器端發送信息的dataoutputstream
        outputstream out = socket.getoutputstream();
        // 裝飾標準輸入流,用于從控制臺輸入
        scanner scanner = new scanner(system.in);
        while (true) {
          string send = scanner.nextline();
          system.out.println("客戶端:" + send);
          byte[] by = send.getbytes("utf-8");
          header header = new header((byte) 1, (byte) 1, (byte) 1, (byte) 1, (byte) 1, "713f17ca614361fb257dc6741332caf2", by.length, 1);
          message message = new message(header, send);
          out.write(message.tobyte());
          out.flush();
          // 把從控制臺得到的信息傳送給服務器
          // out.writeutf("客戶端:" + send);
          // 讀取來自服務器的信息
        }
 
      } finally {
        socket.close();
      }
    } catch (ioexception e) {
      e.printstacktrace();
    }
  }
}

測試結果,ok了

spring+netty服務器搭建的方法

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:http://blog.csdn.net/u012930316/article/details/73743305

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 久久国产乱子伦精品免费不卡 | 羞羞一区二区三区四区片 | 小鸟酱视频在线观看 | 视频高清在线观看 | 成年人视频在线免费看 | 7777奇米| 久久学生精品国产自在拍 | 五月天精品在线 | 亚洲一区二区成人 | 欧美日韩中文国产一区二区三区 | 亚洲AV午夜福利精品香蕉麻豆 | fquer老师 | 免费国产白棉袜踩踏区域 | 996热在线视频 | 我的年轻漂亮继坶三级 | 99在线观看视频免费 | 1769亚洲资源站365在线 | 国内剧情麻豆 | 高中生放荡日记高h娜娜 | 亚洲狠狠婷婷综合久久久久网站 | 久久精品中文字幕 | 91视频a| 午夜影院网站 | 91精品国产免费久久国语蜜臀 | 猛男壮男受bl爽哭了高h | 国产精品久久久久久久久久久搜索 | 四虎免费在线观看 | 亚洲aⅴ天堂 | 欧美日韩人成在线观看 | 草草草视频在线观看 | 天天干夜夜拍 | 国产精品天天看天天爽 | 久久人妻无码毛片A片麻豆 久久热这里只有 精品 | 国产成人免费片在线视频观看 | 亚洲国产在线 | 黑人性xxx | 国产日韩欧美综合在线 | 亚洲第一色视频 | 羞羞私人影院可以直接免费观影吗 | 青青草影院在线观看 | 国产裸露片段精华合集链接 |