本文讲述如何快速将 tio 服务整合到 SpringBoot 项目
首先,你需要在 pom.xml 中引入 tio-core-spring-boot-starter 构件
1<dependency> 2 <groupId>org.t-io</groupId> 3 <artifactId>tio-core-spring-boot-starter</artifactId> 4 <!--此版本号跟着tio主版本号一致即可--> 5 <version>3.3.5.v20190712-RELEASE</version> 6</dependency>
编写服务端程序
一、给SpringBoot Application 主类添加 @EnableTioServerServer 注解
1@SpringBootApplication 2@EnableTioServerServer 3public class TioServerApplication { 4 5 public static void main(String[] args) { 6 SpringApplication.run(TioServerApplication.class, args); 7 } 8}
二、接下来,修改配置文件
1tio: 2 core: 3 server: 4 # websocket port default 9876 5 port: 6789 6 # 心跳时间 7 heartbeat-timeout: 60000 8 # 集群配置 默认关闭 9 cluster: 10 enabled: false 11 # 集群是通过redis的Pub/Sub实现,所以需要配置Redis 12 redis: 13 ip: 127.0.0.1 14 port: 6379 15 all: true 16 group: true 17 ip: true 18 user: true 19 # SSL 配置 20 ssl: 21 enabled: false 22 key-store: 23 password: 24 trust-store:
三、编写消息处理类
1/** 2 * 消息处理 handler, 通过加 {@link TioServerMsgHandler} 注解启用,否则不会启用 3 * 注意: handler 是必须要启用的,否则启动会抛出 {@link TioMsgHandlerNotFoundException} 异常 4 * 5 * @author yangjian 6 */ 7@TioServerMsgHandler 8public class HelloServerMsgHandler implements ServerAioHandler { 9 10 11 /** 12 * 解码:把接收到的ByteBuffer,解码成应用可以识别的业务消息包 13 * 总的消息结构:消息头 + 消息体 14 * 消息头结构: 4个字节,存储消息体的长度 15 * 消息体结构: 对象的json串的byte[] 16 */ 17 @Override 18 public HelloPacket decode(ByteBuffer buffer, int limit, int position, int readableLength, ChannelContext channelContext) throws AioDecodeException 19 { 20 return PacketUtil.decode(buffer, limit, position, readableLength, channelContext); 21 } 22 23 /** 24 * 编码:把业务消息包编码为可以发送的ByteBuffer 25 * 总的消息结构:消息头 + 消息体 26 * 消息头结构: 4个字节,存储消息体的长度 27 * 消息体结构: 对象的json串的byte[] 28 */ 29 @Override 30 public ByteBuffer encode(Packet packet, GroupContext groupContext, ChannelContext channelContext) 31 { 32 return PacketUtil.encode(packet, groupContext, channelContext); 33 } 34 35 36 /** 37 * 处理消息 38 */ 39 @Override 40 public void handler(Packet packet, ChannelContext channelContext) throws Exception { 41 HelloPacket helloPacket = (HelloPacket) packet; 42 byte[] body = helloPacket.getBody(); 43 if (body != null) { 44 String str = new String(body, HelloPacket.CHARSET); 45 System.out.println("收到消息:" + str); 46 47 HelloPacket resppacket = new HelloPacket(); 48 resppacket.setBody(("收到了你的消息,你的消息是:" + str).getBytes(HelloPacket.CHARSET)); 49 Tio.send(channelContext, resppacket); 50 } 51 return; 52 } 53}
四、实现消息实体包
1/** 2 * 消息包实体 3 * 4 * @author yangjian 5 */ 6public class HelloPacket extends Packet { 7 private static final long serialVersionUID = -172060606924066412L; 8 public static final int HEADER_LENGTH = 4;//消息头的长度 9 public static final String CHARSET = "utf-8"; 10 private byte[] body; 11 12 /** 13 * @return the body 14 */ 15 public byte[] getBody() { 16 return body; 17 } 18 19 /** 20 * @param body the body to set 21 */ 22 public void setBody(byte[] body) { 23 this.body = body; 24 } 25}
接下来启动服务端
编写客户端程序
客户端采用 Tio 的常规程序启动,只有三个文件,启动非常简单。
一、编写常量类
1public interface Const { 2 /** 3 * 服务器地址 4 */ 5 public static final String SERVER = "127.0.0.1"; 6 7 /** 8 * 监听端口 9 */ 10 public static final int PORT = 6789; 11 12 /** 13 * 心跳超时时间 14 */ 15 public static final int TIMEOUT = 5000; 16}
二、消息处理类
1public class HelloClientAioHandler implements ClientAioHandler { 2 private static HelloPacket heartbeatPacket = new HelloPacket(); 3 4 5 /** 6 * 解码:把接收到的ByteBuffer,解码成应用可以识别的业务消息包 7 * 总的消息结构:消息头 + 消息体 8 * 消息头结构: 4个字节,存储消息体的长度 9 * 消息体结构: 对象的json串的byte[] 10 */ 11 @Override 12 public HelloPacket decode(ByteBuffer buffer, int limit, int position, int readableLength, ChannelContext channelContext) throws AioDecodeException 13 { 14 return PacketUtil.decode(buffer, limit, position, readableLength, channelContext); 15 } 16 17 /** 18 * 编码:把业务消息包编码为可以发送的ByteBuffer 19 * 总的消息结构:消息头 + 消息体 20 * 消息头结构: 4个字节,存储消息体的长度 21 * 消息体结构: 对象的json串的byte[] 22 */ 23 @Override 24 public ByteBuffer encode(Packet packet, GroupContext groupContext, ChannelContext channelContext) 25 { 26 return PacketUtil.encode(packet, groupContext, channelContext); 27 } 28 29 /** 30 * 处理消息 31 */ 32 @Override 33 public void handler(Packet packet, ChannelContext channelContext) throws Exception { 34 HelloPacket helloPacket = (HelloPacket) packet; 35 byte[] body = helloPacket.getBody(); 36 if (body != null) { 37 String str = new String(body, HelloPacket.CHARSET); 38 System.out.println("收到消息:" + str); 39 } 40 41 return; 42 } 43 44 /** 45 * 此方法如果返回null,框架层面则不会发心跳;如果返回非null,框架层面会定时发本方法返回的消息包 46 */ 47 @Override 48 public HelloPacket heartbeatPacket(ChannelContext channelContext) { 49 return heartbeatPacket; 50 }
三、客户端启动类
1public class HelloClientStarter { 2 //服务器节点 3 public static Node serverNode = new Node(Const.SERVER, Const.PORT); 4 5 //handler, 包括编码、解码、消息处理 6 public static ClientAioHandler tioClientHandler = new HelloClientAioHandler(); 7 8 //事件监听器,可以为null,但建议自己实现该接口,可以参考showcase了解些接口 9 public static ClientAioListener aioListener = null; 10 11 //断链后自动连接的,不想自动连接请设为null 12 private static ReconnConf reconnConf = new ReconnConf(5000L); 13 14 //一组连接共用的上下文对象 15 public static ClientGroupContext clientGroupContext = new ClientGroupContext(tioClientHandler, aioListener, reconnConf); 16 17 public static TioClient tioClient = null; 18 public static ClientChannelContext clientChannelContext = null; 19 20 /** 21 * 启动程序入口 22 */ 23 public static void main(String[] args) throws Exception { 24 clientGroupContext.setHeartbeatTimeout(Const.TIMEOUT); 25 tioClient = new TioClient(clientGroupContext); 26 clientChannelContext = tioClient.connect(serverNode); 27 //连上后,发条消息玩玩 28 send(); 29 } 30 31 private static void send() throws Exception { 32 HelloPacket packet = new HelloPacket(); 33 packet.setBody("hello world".getBytes(HelloPacket.CHARSET)); 34 Tio.send(clientChannelContext, packet); 35 } 36}
启动客户端端,查看终端输出。
服务端输出

原生回调接口支持
跟 handler 一样,其他原生回调接口的使用方法保持不变,只需要在对应的实现类上加上对应的注解就 OK 了。
1//最主要的逻辑处理类,必须要写,否则抛异常 2public class HelloServerMsgHandler implements ServerAioHandler {} 3//可不写,通过加 @TioServerAioListener 注解启用,否则不会启用 4public class HelloServerAioListener implements ServerAioListener {} 5//可不写, 通过加 @TioServerGroupListener 注解启用,否则不会启用 6public class HelloServerGroupListener implements GroupListener{} 7//可不写,通过加 @link TioServerIpStatListener 注解启用,否则不会启用 8public class HelloServerIpStatListener implements IpStatListener {}
这里注意:每个对应的回调接口都需要通过添加注解手动启用,否则默认不启用,不会自动扫描
服务端主动推送
这个也非常简单,只需获取到 TioServerBootstrap ,其他都变得非常简单。
1@RestController 2public class HelloController { 3 4 static Logger logger = LoggerFactory.getLogger(HelloController.class); 5 6 @Autowired 7 private TioServerBootstrap bootstrap; 8 9 @GetMapping("/") 10 public String index() 11 { 12 return "Hello, tio-spring-boot-starter !!!"; 13 } 14 15 /** 16 * 推送消息到客户端 17 * @throws Exception 18 */ 19 @GetMapping("/push") 20 public String pushMessage() throws Exception { 21 HelloPacket packet = new HelloPacket(); 22 packet.setBody("This message is pushed by Tio Server.".getBytes(HelloPacket.CHARSET)); 23 Tio.sendToAll(bootstrap.getServerGroupContext(), packet); 24 logger.info("Push a message to client successfully"); 25 return "Push a message to client successfully"; 26 } 27}
客户端输出截图

SSL 支持
1# SSL 配置 2 ssl: 3 enabled: true 4 key-store: key-store path 5 password: password 6 trust-store: trust-store path
集群支持
1# 集群配置 默认关闭 2 cluster: 3 enabled: false 4 # 集群是通过redis的Pub/Sub实现,所以需要配置Redis 5 redis: 6 ip: 127.0.0.1 7 port: 6379 8 all: true 9 group: true 10 ip: true 11 user: true 12