1
- ## tio-core
1
+ # 独立启动 tcp 服务器
2
2
3
- 使用 tio-boot 内置 tio-core,可以可以tcp-core处理tcp数据, t-io core需要使用单独端口
3
+ 使用 tio-boot 内置 tio-core,可以可以 tcp-core 启动 tcp 服务,处理 tcp 数据, tio-boot 提供了两种处理 tcp 数据数据的方式
4
+
5
+ - 1.t-io core 需要使用单独端口
6
+ - 2.使用 tio-boot tcphander,无须独立的端口,复用 tio-boot server 的端口,同时支持 http 协议和 websocket 协议
7
+
8
+ ## 启动 tcp-server
9
+
10
+ DemoPacket
4
11
5
12
```
6
- package com.litongjava.tio.boot.hello.tioserver;
7
13
import com.litongjava.tio.core.intf.Packet;
8
14
9
15
/**
@@ -23,8 +29,9 @@ public class DemoPacket extends Packet {
23
29
}
24
30
```
25
31
32
+ DemoTioServerListener
33
+
26
34
```
27
- package com.litongjava.tio.boot.hello.tioserver;
28
35
import com.litongjava.tio.core.ChannelContext;
29
36
import com.litongjava.tio.core.Tio;
30
37
import com.litongjava.tio.core.intf.Packet;
@@ -78,9 +85,9 @@ public class DemoTioServerListener implements ServerAioListener {
78
85
}
79
86
```
80
87
81
- ```
82
- package com.litongjava.tio.boot.hello.tioserver;
88
+ DemoTioServerHandler.java
83
89
90
+ ```
84
91
import java.nio.ByteBuffer;
85
92
86
93
import com.litongjava.tio.core.ChannelContext;
@@ -101,7 +108,7 @@ public class DemoTioServerHandler implements ServerAioHandler {
101
108
// 获取由ByteBuffer支持的字节数组
102
109
byte[] bytes = new byte[readableLength];
103
110
buffer.get(bytes);
104
- // 封装为ShowcasePacket
111
+ // 封装为DemoPacket
105
112
DemoPacket imPackage = new DemoPacket();
106
113
imPackage.setBody(bytes);
107
114
return imPackage;
@@ -146,64 +153,68 @@ public class DemoTioServerHandler implements ServerAioHandler {
146
153
}
147
154
```
148
155
156
+ TioServerConfig
157
+
149
158
```
150
- package com.litongjava.tio.boot.hello.tioserver ;
159
+ package demo.tcp.config ;
151
160
152
161
import java.io.IOException;
153
162
163
+ import com.litongjava.jfinal.aop.annotation.AConfiguration;
164
+ import com.litongjava.jfinal.aop.annotation.AInitialization;
154
165
import com.litongjava.tio.server.ServerTioConfig;
155
166
import com.litongjava.tio.server.TioServer;
156
167
import com.litongjava.tio.server.intf.ServerAioHandler;
157
168
import com.litongjava.tio.server.intf.ServerAioListener;
158
169
159
- public class DemoTioServer {
160
- // handler, 包括编码、解码、消息处理
161
- ServerAioHandler serverHandler = new DemoTioServerHandler();
162
- // 事件监听器,可以为null,但建议自己实现该接口,可以参考showcase了解些接口
163
- ServerAioListener serverListener = new DemoTioServerListener();
164
- // 配置对象
165
- ServerTioConfig tioServerConfig = new ServerTioConfig(serverHandler, serverListener);
170
+ import demo.tcp.server.DemoTioServerHandler;
171
+ import demo.tcp.server.DemoTioServerListener;
166
172
167
- /**
168
- * 启动程序入口
169
- */
170
- public void start() throws IOException {
173
+ @AConfiguration
174
+ public class TioServerConfig {
175
+
176
+ @AInitialization
177
+ public void demoTioServer() {
178
+ // handler, 包括编码、解码、消息处理
179
+ ServerAioHandler serverHandler = new DemoTioServerHandler();
180
+ // 事件监听器,可以为null,但建议自己实现该接口,可以参考showcase了解些接口
181
+ ServerAioListener serverListener = new DemoTioServerListener();
182
+ // 配置对象
183
+ ServerTioConfig tioServerConfig = new ServerTioConfig("tcp-server", serverHandler, serverListener);
171
184
172
185
// 设置心跳,-1 取消心跳
173
186
tioServerConfig.setHeartbeatTimeout(-1);
174
187
// TioServer对象
175
188
TioServer tioServer = new TioServer(tioServerConfig);
176
189
177
190
// 启动服务
178
- tioServer.start(null, 6789);
179
- }
180
- }
181
- ```
182
-
183
- ```
184
- package com.litongjava.tio.boot.hello.config;
185
-
186
- import java.io.IOException;
187
-
188
- import com.litongjava.jfinal.aop.annotation.Bean;
189
- import com.litongjava.jfinal.aop.annotation.Configuration;
190
- import com.litongjava.tio.boot.hello.tioserver.DemoTioServer;
191
-
192
- @AConfiguration
193
- public class TioServerConfig {
194
-
195
- @ABean
196
- public DemoTioServer demoTioServer() {
197
- DemoTioServer demoTioServer = new DemoTioServer();
198
191
try {
199
- demoTioServer .start();
192
+ tioServer .start(null, 9998 );
200
193
} catch (IOException e) {
201
194
e.printStackTrace();
202
195
}
203
- return demoTioServer;
204
196
}
197
+ }
198
+ ```
205
199
200
+ 启动类
201
+
202
+ ```
203
+ package demo.tcp;
204
+
205
+ import com.litongjava.hotswap.wrapper.tio.boot.TioApplicationWrapper;
206
+ import com.litongjava.jfinal.aop.annotation.AComponentScan;
207
+
208
+ @AComponentScan
209
+ public class Main {
210
+ public static void main(String[] args) {
211
+ long start = System.currentTimeMillis();
212
+ TioApplicationWrapper.run(Main.class, args);
213
+ long end = System.currentTimeMillis();
214
+ System.out.println((end - start) + "(ms)");
215
+ }
206
216
}
217
+
207
218
```
208
219
209
220
上面的代码是一个使用 Java TIO 网络框架实现的简单服务器应用的示例。让我们逐部分进行解释:
@@ -231,27 +242,217 @@ public class TioServerConfig {
231
242
- ` encode ` :将 ` DemoPacket ` 对象转换为传输的原始数据。
232
243
- ` handler ` :处理接收到的数据包并发送响应。
233
244
234
- #### ` DemoTioServer ` 类(服务器配置和启动)
235
-
236
- - ** 目的** :设置并启动 Tio 服务器。
237
- - ** 主要元素** :
238
- - 配置心跳超时、服务器处理器和监听器。
239
- - 在指定端口(` 6789 ` )上启动服务器。
240
-
241
245
#### ` TioServerConfig ` 类(tio-boot 配置)
242
246
243
- - ** 包名** :` com.litongjava.tio.boot.hello.config `
244
- - ** 目的** :使用 tio-boot 框架的注解来配置并启动 ` DemoTioServer ` 。
247
+ - ** 目的** :使用 tio-boot 框架的注解来配置并启动 Tio 服务器。
245
248
- ** 主要元素** :
246
249
- 用 ` @AConfiguration ` 注解标记,表示这是一个 tio-boot 配置类。
247
- - 包含一个用 ` @ABean ` 注解的方法 ` demoTioServer ` ,该方法启动 ` DemoTioServer ` 。
250
+ - 包含一个用 ` @AInitialization ` 注解的方法 ` demoTioServer ` ,tio-boot 框架启动时会执行改方法,该方法启动 tioServer
251
+ - 配置心跳超时、服务器处理器和监听器。
252
+ - 在指定端口(` 6789 ` )上启动服务器。
248
253
249
254
#### 整体流程
250
255
251
256
1 . ** 数据包定义** :自定义数据包(` DemoPacket ` )来携带数据。
252
257
2 . ** 事件处理** :` DemoTioServerListener ` 监听服务器事件,如连接、断开连接和心跳。
253
258
3 . ** 数据处理** :` DemoTioServerHandler ` 处理数据包的编码和解码,并处理传入的消息。
254
- 4 . ** 服务器设置和启动** :` DemoTioServer ` 配置并启动 Tio 服务器,使用定义的处理器和监听器。
255
- 5 . ** tio-boot 集成** :` TioServerConfig ` 使用 tio-boot 来管理 ` DemoTioServer ` 的生命周期和配置。
259
+ 4 . ** 服务器设置和启动** :` TioServerConfig ` 配置并启动 Tio 服务器,使用定义的处理器和监听器。
260
+
261
+ 这段代码演示了 TIO 服务器的基本但完整的设置,包括数据包处理、事件监听、消息处理,以及与 tio-boot 框架的集成,便于管理和配置。
262
+
263
+ ## 启动 tcp client
264
+
265
+ Tio-Boot 同样内置了 tcp-client,你可是使用 tcpClient 向服务端发送消息
266
+
267
+ DemoClientAioHandler
268
+
269
+ ```
270
+ package demo.tcp.client;
271
+
272
+ import java.nio.ByteBuffer;
273
+
274
+ import com.litongjava.tio.client.intf.ClientAioHandler;
275
+ import com.litongjava.tio.core.ChannelContext;
276
+ import com.litongjava.tio.core.TioConfig;
277
+ import com.litongjava.tio.core.exception.TioDecodeException;
278
+ import com.litongjava.tio.core.intf.Packet;
279
+
280
+ import demo.tcp.server.DemoPacket;
281
+ import lombok.extern.slf4j.Slf4j;
282
+
283
+ @Slf4j
284
+ public class DemoClientAioHandler implements ClientAioHandler {
285
+
286
+ /**
287
+ * 解码:把接收到的ByteBuffer解码成应用可以识别的业务消息包
288
+ */
289
+ @Override
290
+ public Packet decode(ByteBuffer buffer, int limit, int position, int readableLength, ChannelContext var5)
291
+ throws TioDecodeException {
292
+ log.info("buffer:{}", buffer);
293
+ // 转换前准备ByteBuffer
294
+ int length = buffer.remaining();
295
+ // 获取由ByteBuffer支持的字节数组
296
+ byte[] bytes = new byte[length];
297
+ buffer.get(bytes);
298
+ // 封装为DemoPacket
299
+ DemoPacket imPackage = new DemoPacket();
300
+ imPackage.setBody(bytes);
301
+ return imPackage;
302
+
303
+ }
304
+
305
+ /**
306
+ * 编码:把业务消息包编码为可以发送的ByteBuffer
307
+ */
308
+ @Override
309
+ public ByteBuffer encode(Packet packet, TioConfig tioConfig, ChannelContext chanelContext) {
310
+
311
+ DemoPacket helloPacket = (DemoPacket) packet;
312
+ byte[] body = helloPacket.getBody();
313
+ // ByteBuffer的总长度是消息体长度
314
+ int bodyLength = body.length;
315
+ log.info("encode:{}", bodyLength);
316
+
317
+ // 创建一个新的ByteBuffer
318
+ ByteBuffer buffer = ByteBuffer.allocate(bodyLength);
319
+ // 设置字节序
320
+ buffer.order(tioConfig.getByteOrder());
321
+ // 消息消息体
322
+ buffer.put(body);
323
+ return buffer;
324
+ }
325
+
326
+ /**
327
+ * 处理消息
328
+ */
329
+ @Override
330
+ public void handler(Packet packet, ChannelContext var2) throws Exception {
331
+ log.info("handler");
332
+ DemoPacket helloPacket = (DemoPacket) packet;
333
+ byte[] body = helloPacket.getBody();
334
+ if (body != null) {
335
+ String str = new String(body);
336
+ System.out.println("received::" + str);
337
+ }
338
+ }
339
+
340
+ /**
341
+ * 此方法如果返回null,框架层面则不会发出心跳,如果返回非null,框架层面会定时发送本方法返回的消息包
342
+ */
343
+ @Override
344
+ public Packet heartbeatPacket(ChannelContext var1) {
345
+ return null;
346
+ }
347
+ }
348
+ ```
349
+
350
+ DemoTioClient
351
+
352
+ ```
353
+ package demo.tcp.client;
354
+
355
+ import java.io.IOException;
356
+
357
+ import com.litongjava.tio.client.ClientChannelContext;
358
+ import com.litongjava.tio.client.ClientTioConfig;
359
+ import com.litongjava.tio.client.ReconnConf;
360
+ import com.litongjava.tio.client.TioClient;
361
+ import com.litongjava.tio.client.intf.ClientAioHandler;
362
+ import com.litongjava.tio.client.intf.ClientAioListener;
363
+ import com.litongjava.tio.core.Node;
364
+ import com.litongjava.tio.core.Tio;
365
+
366
+ import demo.tcp.server.DemoPacket;
367
+
368
+ public class DemoTioClient {
369
+ /**
370
+ * 启动程序
371
+ */
372
+ public static void main(String[] args) throws Exception {
373
+
374
+ // 服务器节点
375
+ Node serverNode = new Node("127.0.0.1", 9998);
376
+ // handler,包含编解码,消息处理
377
+ ClientAioHandler clientAioHandler = new DemoClientAioHandler();
378
+ // 初始化
379
+ ClientChannelContext clientChannelContext = init(serverNode, clientAioHandler);
380
+ // 发送消息
381
+ send(clientChannelContext, "Hello,World");
382
+ }
383
+
384
+ public static ClientChannelContext init(Node serverNode, ClientAioHandler clientAioHandler)
385
+ throws IOException, Exception {
386
+
387
+ // 事件监听器,可以为null,但是建议自己实现该接口,可以参考showcase
388
+ ClientAioListener clientAioListener = null;
389
+
390
+ // 断链后自动连接,不自动连接设置为null
391
+ ReconnConf reconnConf = new ReconnConf(50000L);
392
+ // 共用上下文对象
393
+ ClientTioConfig clientTioConfig = new ClientTioConfig(clientAioHandler, clientAioListener, reconnConf);
394
+
395
+ // 发送消息客户端
396
+ TioClient tioClient;
397
+ // 客户端通道上下文,连接服务器后获得
398
+ ClientChannelContext clientChannelContext;
399
+
400
+ // 设置心跳时间
401
+ clientTioConfig.setHeartbeatTimeout(0);
402
+ // 初始化client
403
+ tioClient = new TioClient(clientTioConfig);
404
+ // 连接服务器
405
+ clientChannelContext = tioClient.connect(serverNode);
406
+ return clientChannelContext;
407
+ }
408
+
409
+ private static void send(ClientChannelContext clientChannelContext, String message) {
410
+ DemoPacket helloPacket = new DemoPacket();
411
+ helloPacket.setBody(message.getBytes());
412
+ Tio.send(clientChannelContext, helloPacket);
413
+ }
414
+ }
415
+ ```
416
+
417
+ ### 日志
418
+
419
+ 测试成功后显示的日志如下
420
+
421
+ 客户端日志
422
+
423
+ ```
424
+ 18:50:14.715 [tio-timer-reconnect-1] ERROR com.litongjava.tio.client.TioClient - closeds:0, connections:0
425
+ 18:50:14.715 [tio-timer-heartbeat1] WARN com.litongjava.tio.client.TioClient - The user has cancelled the heartbeat sending function at the frame level, and asks the user to complete the heartbeat mechanism by himsel
426
+ 18:50:14.992 [tio-group-2] INFO com.litongjava.tio.client.ConnectionCompletionHandler - connected to 127.0.0.1:9998
427
+ 18:50:14.995 [tio-worker-2] INFO demo.tcp.client.DemoClientAioHandler - encode:11
428
+ 18:50:14.997 [tio-group-3] DEBUG com.litongjava.tio.core.ChannelContext - server:127.0.0.1:9998, client:0:0:0:0:0:0:0:0:1311 Sent
429
+ 18:50:14.998 [tio-group-4] INFO demo.tcp.client.DemoClientAioHandler - buffer:java.nio.HeapByteBuffer[pos=0 lim=51 cap=20480]
430
+ 18:50:14.999 [tio-group-4] DEBUG com.litongjava.tio.core.task.DecodeRunnable - server:127.0.0.1:9998, client:0:0:0:0:0:0:0:0:1311, Unpacking to get a packet:
431
+ 18:50:15.000 [tio-group-4] INFO demo.tcp.client.DemoClientAioHandler - handler
432
+ received::收到了你的消息,你的消息是:Hello,World
433
+ 18:50:15.000 [tio-group-4] DEBUG com.litongjava.tio.core.task.DecodeRunnable - server:127.0.0.1:9998, client:0:0:0:0:0:0:0:0:1311,After grouping the packets, the data just ran out
434
+
435
+ ```
436
+
437
+ 服务端日志
438
+
439
+ ```
440
+ 18:50:14.997 [tio-group-10] INFO demo.tcp.server.DemoTioServerHandler - buffer:java.nio.HeapByteBuffer[pos=0 lim=11 cap=20480]
441
+ 18:50:14.997 [tio-group-10] DEBUG com.litongjava.tio.core.task.DecodeRunnable - server:0.0.0.0:9998, client:127.0.0.1:1311, Unpacking to get a packet:
442
+ 18:50:14.997 [tio-group-10] INFO demo.tcp.server.DemoTioServerHandler - received:Hello,World
443
+ 18:50:14.997 [tio-group-10] INFO demo.tcp.server.DemoTioServerHandler - sendMessage:收到了你的消息,你的消息是:Hello,World
444
+ 18:50:14.997 [tio-group-10] INFO demo.tcp.server.DemoTioServerHandler - 开始响应
445
+ 18:50:14.997 [tio-group-10] INFO demo.tcp.server.DemoTioServerHandler - 响应完成
446
+ 18:50:14.997 [tio-group-10] DEBUG com.litongjava.tio.core.task.DecodeRunnable - server:0.0.0.0:9998, client:127.0.0.1:1311,After grouping the packets, the data just ran out
447
+ 18:50:14.998 [tio-worker-5] INFO demo.tcp.server.DemoTioServerHandler - encode:51
448
+ 18:50:14.998 [tio-group-11] DEBUG com.litongjava.tio.core.ChannelContext - server:0.0.0.0:9998, client:127.0.0.1:1311 Sent
449
+ 18:50:27.310 [tio-worker-6] INFO demo.tcp.server.DemoTioServerListener - 关闭后清除认证信息
450
+ 18:50:27.310 [tio-worker-6] DEBUG com.litongjava.tio.core.maintain.Tokens - tcp-server, server:0.0.0.0:9998, client:127.0.0.1:1311, 并没有绑定Token
451
+ 18:50:27.310 [tio-worker-6] DEBUG com.litongjava.tio.core.maintain.Users - tcp-server, server:0.0.0.0:9998, client:127.0.0.1:1311, 并没有绑定用户
452
+ 18:50:27.310 [tio-worker-6] DEBUG com.litongjava.tio.core.maintain.Tokens - tcp-server, server:0.0.0.0:9998, client:127.0.0.1:1311, 并没有绑定Token
453
+
454
+ ```
455
+
456
+ ### 测试代码地址
256
457
257
- 这段代码演示了 TIO 服务器的基本但完整的设置,包括数据包处理、事件监听、消息处理,以及与 tio-boot 框架的集成,便于管理和配置。
458
+ https://github.com/litongjava/java-ee- tio-boot-study/tree/main/tio-boot-latest-study/tio-boot-tcp-server-demo01
0 commit comments