Skip to content

Commit 3d7ec16

Browse files
author
litongjava
committed
add DemoTioClient
1 parent 0d05c70 commit 3d7ec16

File tree

1 file changed

+255
-54
lines changed
  • docs/zh/06_内置组件

1 file changed

+255
-54
lines changed

docs/zh/06_内置组件/06.md

+255-54
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1-
## tio-core
1+
# 独立启动 tcp 服务器
22

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
411

512
```
6-
package com.litongjava.tio.boot.hello.tioserver;
713
import com.litongjava.tio.core.intf.Packet;
814
915
/**
@@ -23,8 +29,9 @@ public class DemoPacket extends Packet {
2329
}
2430
```
2531

32+
DemoTioServerListener
33+
2634
```
27-
package com.litongjava.tio.boot.hello.tioserver;
2835
import com.litongjava.tio.core.ChannelContext;
2936
import com.litongjava.tio.core.Tio;
3037
import com.litongjava.tio.core.intf.Packet;
@@ -78,9 +85,9 @@ public class DemoTioServerListener implements ServerAioListener {
7885
}
7986
```
8087

81-
```
82-
package com.litongjava.tio.boot.hello.tioserver;
88+
DemoTioServerHandler.java
8389

90+
```
8491
import java.nio.ByteBuffer;
8592
8693
import com.litongjava.tio.core.ChannelContext;
@@ -101,7 +108,7 @@ public class DemoTioServerHandler implements ServerAioHandler {
101108
// 获取由ByteBuffer支持的字节数组
102109
byte[] bytes = new byte[readableLength];
103110
buffer.get(bytes);
104-
// 封装为ShowcasePacket
111+
// 封装为DemoPacket
105112
DemoPacket imPackage = new DemoPacket();
106113
imPackage.setBody(bytes);
107114
return imPackage;
@@ -146,64 +153,68 @@ public class DemoTioServerHandler implements ServerAioHandler {
146153
}
147154
```
148155

156+
TioServerConfig
157+
149158
```
150-
package com.litongjava.tio.boot.hello.tioserver;
159+
package demo.tcp.config;
151160
152161
import java.io.IOException;
153162
163+
import com.litongjava.jfinal.aop.annotation.AConfiguration;
164+
import com.litongjava.jfinal.aop.annotation.AInitialization;
154165
import com.litongjava.tio.server.ServerTioConfig;
155166
import com.litongjava.tio.server.TioServer;
156167
import com.litongjava.tio.server.intf.ServerAioHandler;
157168
import com.litongjava.tio.server.intf.ServerAioListener;
158169
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;
166172
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);
171184
172185
// 设置心跳,-1 取消心跳
173186
tioServerConfig.setHeartbeatTimeout(-1);
174187
// TioServer对象
175188
TioServer tioServer = new TioServer(tioServerConfig);
176189
177190
// 启动服务
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();
198191
try {
199-
demoTioServer.start();
192+
tioServer.start(null, 9998);
200193
} catch (IOException e) {
201194
e.printStackTrace();
202195
}
203-
return demoTioServer;
204196
}
197+
}
198+
```
205199

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+
}
206216
}
217+
207218
```
208219

209220
上面的代码是一个使用 Java TIO 网络框架实现的简单服务器应用的示例。让我们逐部分进行解释:
@@ -231,27 +242,217 @@ public class TioServerConfig {
231242
- `encode`:将 `DemoPacket` 对象转换为传输的原始数据。
232243
- `handler`:处理接收到的数据包并发送响应。
233244

234-
#### `DemoTioServer` 类(服务器配置和启动)
235-
236-
- **目的**:设置并启动 Tio 服务器。
237-
- **主要元素**
238-
- 配置心跳超时、服务器处理器和监听器。
239-
- 在指定端口(`6789`)上启动服务器。
240-
241245
#### `TioServerConfig` 类(tio-boot 配置)
242246

243-
- **包名**`com.litongjava.tio.boot.hello.config`
244-
- **目的**:使用 tio-boot 框架的注解来配置并启动 `DemoTioServer`
247+
- **目的**:使用 tio-boot 框架的注解来配置并启动 Tio 服务器。
245248
- **主要元素**
246249
-`@AConfiguration` 注解标记,表示这是一个 tio-boot 配置类。
247-
- 包含一个用 `@ABean` 注解的方法 `demoTioServer`,该方法启动 `DemoTioServer`
250+
- 包含一个用 `@AInitialization` 注解的方法 `demoTioServer`,tio-boot 框架启动时会执行改方法,该方法启动 tioServer
251+
- 配置心跳超时、服务器处理器和监听器。
252+
- 在指定端口(`6789`)上启动服务器。
248253

249254
#### 整体流程
250255

251256
1. **数据包定义**:自定义数据包(`DemoPacket`)来携带数据。
252257
2. **事件处理**`DemoTioServerListener` 监听服务器事件,如连接、断开连接和心跳。
253258
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+
### 测试代码地址
256457

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

Comments
 (0)