├── .gitignore
├── README.md
└── netty4-demos
├── .gitignore
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── waylau
│ │ ├── java
│ │ └── demo
│ │ │ ├── aio
│ │ │ ├── AsyncEchoClient.java
│ │ │ └── AsyncEchoServer.java
│ │ │ ├── buffer
│ │ │ └── ByteBufferDemo.java
│ │ │ ├── concurrent
│ │ │ └── ThreadPoolExecutorDemo.java
│ │ │ ├── net
│ │ │ ├── BlockingEchoClient.java
│ │ │ └── BlockingEchoServer.java
│ │ │ ├── nio
│ │ │ ├── NonBlockingEchoClient.java
│ │ │ └── NonBlokingEchoServer.java
│ │ │ └── reactor
│ │ │ ├── basic
│ │ │ ├── Acceptor.java
│ │ │ ├── AsyncHandler.java
│ │ │ ├── BasicReactorDemo.java
│ │ │ ├── Handler.java
│ │ │ └── Reactor.java
│ │ │ ├── client
│ │ │ ├── ClientDemo.java
│ │ │ ├── Connector.java
│ │ │ ├── Handler.java
│ │ │ └── NIOClient.java
│ │ │ └── mainsub
│ │ │ ├── Acceptor.java
│ │ │ ├── AsyncHandler.java
│ │ │ ├── MainSubReactorDemo.java
│ │ │ ├── Reactor.java
│ │ │ └── SubReactor.java
│ │ └── netty
│ │ ├── TcpClient.java
│ │ ├── demo
│ │ ├── buffer
│ │ │ ├── ByteBufCompositeBufferDemo.java
│ │ │ ├── ByteBufDemo.java
│ │ │ ├── ByteBufDirectBufferDemo.java
│ │ │ └── ByteBufHeapBufferDemo.java
│ │ ├── codec
│ │ │ ├── Msg.java
│ │ │ ├── MsgHeader.java
│ │ │ ├── MsgType.java
│ │ │ ├── MyClient.java
│ │ │ ├── MyClientHandler.java
│ │ │ ├── MyCodec.java
│ │ │ ├── MyDecoder.java
│ │ │ ├── MyEncoder.java
│ │ │ ├── MyServer.java
│ │ │ ├── MyServerHandler.java
│ │ │ ├── jackcon
│ │ │ │ ├── JacksonBean.java
│ │ │ │ ├── JacksonClient.java
│ │ │ │ ├── JacksonClientHandler.java
│ │ │ │ ├── JacksonClientInitializer.java
│ │ │ │ ├── JacksonDecoder.java
│ │ │ │ ├── JacksonEncoder.java
│ │ │ │ ├── JacksonMapper.java
│ │ │ │ ├── JacksonServer.java
│ │ │ │ ├── JacksonServerHandler.java
│ │ │ │ ├── JacksonServerInitializer.java
│ │ │ │ └── package-info.java
│ │ │ ├── serialization
│ │ │ │ ├── SerializationBean.java
│ │ │ │ ├── SerializationClient.java
│ │ │ │ ├── SerializationClientHandler.java
│ │ │ │ ├── SerializationClientInitializer.java
│ │ │ │ ├── SerializationServer.java
│ │ │ │ ├── SerializationServerHandler.java
│ │ │ │ ├── SerializationServerInitializer.java
│ │ │ │ └── package-info.java
│ │ │ └── 消息格式.md
│ │ ├── decoder
│ │ │ ├── MyLineBasedFrameDecoder.java
│ │ │ ├── MyLineBasedFrameDecoderChannelInitializer.java
│ │ │ ├── MyLineBasedFrameDecoderServer.java
│ │ │ └── MyLineBasedFrameDecoderServerHandler.java
│ │ ├── discard
│ │ │ ├── DiscardServer.java
│ │ │ └── DiscardServerHandler.java
│ │ ├── echo
│ │ │ ├── DatagramChannelEchoClient.java
│ │ │ ├── DatagramChannelEchoClientHandler.java
│ │ │ ├── DatagramChannelEchoServer.java
│ │ │ ├── DatagramChannelEchoServerHandler.java
│ │ │ ├── EchoClient.java
│ │ │ ├── EchoClientHandler.java
│ │ │ ├── EchoServer.java
│ │ │ ├── EchoServerHandler.java
│ │ │ ├── EpollEchoServer.java
│ │ │ ├── LocalEchoServer.java
│ │ │ └── OioEchoServer.java
│ │ ├── encoder
│ │ │ ├── Msg.java
│ │ │ ├── MsgHeader.java
│ │ │ ├── MsgType.java
│ │ │ ├── MyClient.java
│ │ │ ├── MyClientHandler.java
│ │ │ ├── MyDecoder.java
│ │ │ ├── MyEncoder.java
│ │ │ ├── MyServer.java
│ │ │ ├── MyServerHandler.java
│ │ │ └── 消息格式.md
│ │ ├── factorial
│ │ │ ├── BigIntegerDecoder.java
│ │ │ ├── FactorialClient.java
│ │ │ ├── FactorialClientHandler.java
│ │ │ ├── FactorialClientInitializer.java
│ │ │ ├── FactorialServer.java
│ │ │ ├── FactorialServerHandler.java
│ │ │ ├── FactorialServerInitializer.java
│ │ │ └── NumberEncoder.java
│ │ ├── file
│ │ │ ├── FileClient.java
│ │ │ ├── FileClientHandler.java
│ │ │ ├── FileServer.java
│ │ │ ├── FileServerHandler.java
│ │ │ └── package-info.java
│ │ ├── heartbeat
│ │ │ ├── HeartbeatHandlerInitializer.java
│ │ │ ├── HeartbeatServer.java
│ │ │ ├── HeartbeatServerHandler.java
│ │ │ └── package-info.java
│ │ ├── http2
│ │ │ ├── client
│ │ │ │ ├── Http2Client.java
│ │ │ │ ├── Http2ClientInitializer.java
│ │ │ │ ├── Http2SettingsHandler.java
│ │ │ │ └── HttpResponseHandler.java
│ │ │ └── server
│ │ │ │ ├── Http1ServerHandler.java
│ │ │ │ ├── Http2OrHttpHandler.java
│ │ │ │ ├── Http2Server.java
│ │ │ │ ├── Http2ServerHandler.java
│ │ │ │ ├── Http2ServerHandlerBuilder.java
│ │ │ │ └── Http2ServerInitializer.java
│ │ ├── httpserver
│ │ │ ├── HttpServer.java
│ │ │ ├── HttpServerChannelInitializer.java
│ │ │ └── HttpServerHandler.java
│ │ ├── pojo
│ │ │ ├── MessageToByteTimeEncoder.java
│ │ │ ├── TimeClient.java
│ │ │ ├── TimeClientHandler.java
│ │ │ ├── TimeDecoder.java
│ │ │ ├── TimeEncoder.java
│ │ │ ├── TimeServer.java
│ │ │ ├── TimeServerHandler.java
│ │ │ └── UnixTime.java
│ │ ├── protocol
│ │ │ ├── ClientTask.java
│ │ │ ├── MsgType.java
│ │ │ ├── ProtocolClient.java
│ │ │ ├── ProtocolClientHandler.java
│ │ │ ├── ProtocolClientTest.java
│ │ │ ├── ProtocolDecoder.java
│ │ │ ├── ProtocolDecoderDeprecation.java
│ │ │ ├── ProtocolEncoder.java
│ │ │ ├── ProtocolHeader.java
│ │ │ ├── ProtocolMsg.java
│ │ │ ├── ProtocolServer.java
│ │ │ ├── ProtocolServerHandler.java
│ │ │ ├── package-info.java
│ │ │ └── 消息格式.md
│ │ ├── securechat
│ │ │ ├── SecureChatClient.java
│ │ │ ├── SecureChatClientHandler.java
│ │ │ ├── SecureChatClientInitializer.java
│ │ │ ├── SecureChatServer.java
│ │ │ ├── SecureChatServerHandler.java
│ │ │ └── SecureChatServerInitializer.java
│ │ ├── secureecho
│ │ │ ├── EchoClient.java
│ │ │ ├── EchoClientChannelInitializer.java
│ │ │ ├── EchoClientHandler.java
│ │ │ ├── EchoServer.java
│ │ │ ├── EchoServerChannelInitializer.java
│ │ │ ├── EchoServerHandler.java
│ │ │ └── SslContextFactory.java
│ │ ├── simplechat
│ │ │ ├── SimpleChatClient.java
│ │ │ ├── SimpleChatClientHandler.java
│ │ │ ├── SimpleChatClientInitializer.java
│ │ │ ├── SimpleChatServer.java
│ │ │ ├── SimpleChatServerHandler.java
│ │ │ └── SimpleChatServerInitializer.java
│ │ ├── telnet
│ │ │ ├── TelnetClient.java
│ │ │ ├── TelnetClientHandler.java
│ │ │ ├── TelnetClientInitializer.java
│ │ │ ├── TelnetServer.java
│ │ │ ├── TelnetServerHandler.java
│ │ │ └── TelnetServerInitializer.java
│ │ ├── time
│ │ │ ├── TimeClient.java
│ │ │ ├── TimeClientHandler.java
│ │ │ ├── TimeServer.java
│ │ │ └── TimeServerHandler.java
│ │ └── websocketchat
│ │ │ ├── HttpRequestHandler.java
│ │ │ ├── TextWebSocketFrameHandler.java
│ │ │ ├── WebSocketChatServer.java
│ │ │ └── WebSocketChatServerInitializer.java
│ │ └── util
│ │ ├── ByteObjConverter.java
│ │ └── package-info.java
└── resources
│ ├── WebsocketChatClient.html
│ └── ssl
│ ├── nettyClient.cer
│ ├── nettyClient.jks
│ ├── nettyServer.cer
│ └── nettyServer.jks
└── test
└── java
└── com
└── waylau
└── netty
└── demo
├── decoder
└── FixedLengthFrameDecoderTest.java
└── encoder
├── AbsIntegerEncoder.java
└── AbsIntegerEncoderTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | /.idea/
3 | /.settings/
4 | .classpath
5 | .project
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Netty demos. (Netty 案例大全)
2 |
3 | Demos of [Netty 4.x User Guide](https://github.com/waylau/netty-4-user-guide) 《Netty 4.x 用户指南》/《Netty原理解析与开发实战》,文中用到的例子源码。
4 |
5 |
6 | ## 版本
7 |
8 | 涉及的相关技术及版本如下。
9 |
10 | * Netty 4.1.52.Final
11 | * Jackson 2.10.1
12 | * JUnit 5.5.2
13 |
14 |
15 | ## 示例
16 |
17 | 包含示例如下:
18 |
19 | * [Java标准I/O实现Echo服务器、客户端](netty4-demos/src/main/java/com/waylau/java/demo/net)
20 | * [Java NIO实现Echo服务器、客户端](netty4-demos/src/main/java/com/waylau/java/demo/nio)
21 | * [Java AIO实现Echo服务器、客户端](netty4-demos/src/main/java/com/waylau/java/demo/aio)
22 | * [Netty实现Echo服务器、客户端](netty4-demos/src/main/java/com/waylau/netty/demo/echo)
23 | * [Netty实现丢弃服务器](netty4-demos/src/main/java/com/waylau/netty/demo/discard)
24 | * [Netty实现时间服务器](netty4-demos/src/main/java/com/waylau/netty/demo/time)
25 | * [Java ByteBuffer使用案例](netty4-demos/src/main/java/com/waylau/java/demo/buffer)
26 | * [Netty ByteBuf使用案例](netty4-demos/src/main/java/com/waylau/netty/demo/buffer)
27 | * [Netty ByteBuf的三种使用模式](netty4-demos/src/main/java/com/waylau/netty/demo/buffer)
28 | * [Netty实现无连接协议Echo服务器、客户端](netty4-demos/src/main/java/com/waylau/netty/demo/echo)
29 | * [Java线程池示例](netty4-demos/src/main/java/com/waylau/java/demo/concurrent/ThreadPoolExecutorDemo.java)
30 | * [Java Reactor示例](netty4-demos/src/main/java/com/waylau/java/demo/reactor)
31 | * [自定义基于换行的解码器](netty4-demos/src/main/java/com/waylau/java/demo/decoder)
32 | * [TCP客户端](netty4-demos/src/main/java/com/waylau/java/TcpClient.java)
33 | * [自定义编码器](netty4-demos/src/main/java/com/waylau/java/demo/encoder)
34 | * [自定义编解码器](netty4-demos/src/main/java/com/waylau/java/demo/codec)
35 | * [实现心跳机制](netty4-demos/src/main/java/com/waylau/java/demo/heartbeat)
36 | * [基于Netty的对象序列化](netty4-demos/src/main/java/com/waylau/java/demo/codec/serialization)
37 | * [基于Jackson的JSON序列化](netty4-demos/src/main/java/com/waylau/java/demo/codec/jackcon)
38 | * [基于SSL/TSL的双向认证Echo服务器和客户端](netty4-demos/src/main/java/com/waylau/java/demo/secureecho)
39 | * [基于HTTP的Web服务器](netty4-demos/src/main/java/com/waylau/java/demo/httpserver)
40 | * [基于HTTP/2的Web服务器和客户端](netty4-demos/src/main/java/com/waylau/java/demo/http2)
41 | * [基于WebSocket的聊天室](netty4-demos/src/main/java/com/waylau/java/demo/websocketchat)
42 | * [lite-monitoring](https://github.com/waylau/lite-monitoring)
43 | * [lite-monitoring-ui](https://github.com/waylau/lite-monitoring-ui)
44 | * 陆续整理中...
45 |
46 | ## 配套书籍
47 |
48 | * 开源书《[Netty 4.x User Guide](https://github.com/waylau/netty-4-user-guide)》
49 | * 正式出版物《[Netty原理解析与开发实战](https://book.douban.com/subject/35317298/)》
--------------------------------------------------------------------------------
/netty4-demos/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 | /.idea/
3 | /.settings/
4 | .classpath
5 | .project
6 | *.iml
--------------------------------------------------------------------------------
/netty4-demos/pom.xml:
--------------------------------------------------------------------------------
1 |
4 | 4.0.0
5 |
6 | com.waylau
7 | netty4-demos
8 | 1.0.0
9 | jar
10 |
11 | netty4-demos
12 | https://waylau.com
13 |
14 |
15 | UTF-8
16 | 1.8
17 | ${maven.compiler.source}
18 | 4.1.66.Final
19 | 2.10.1
20 | 5.5.2
21 |
22 |
23 |
24 |
25 | maven-compiler-plugin
26 | 3.8.1
27 |
28 |
29 |
30 |
31 |
32 |
33 | io.netty
34 | netty-all
35 | ${netty-all.version}
36 |
37 |
38 | com.fasterxml.jackson.core
39 | jackson-core
40 | ${jackson.core.version}
41 |
42 |
43 | com.fasterxml.jackson.core
44 | jackson-databind
45 | ${jackson.core.version}
46 |
47 |
48 |
49 | org.junit.jupiter
50 | junit-jupiter
51 | ${junit.jupiter.version}
52 | test
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/java/demo/aio/AsyncEchoClient.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Welcome to https://waylau.com
3 | */
4 | package com.waylau.java.demo.aio;
5 |
6 | import java.io.BufferedReader;
7 | import java.io.IOException;
8 | import java.io.InputStreamReader;
9 | import java.net.InetSocketAddress;
10 | import java.net.UnknownHostException;
11 | import java.nio.ByteBuffer;
12 | import java.nio.channels.AsynchronousSocketChannel;
13 |
14 | /**
15 | * Async Echo Client.
16 | *
17 | * @since 1.0.0 2019年9月30日
18 | * @author Way Lau
19 | */
20 | public class AsyncEchoClient {
21 |
22 | /**
23 | * @param args
24 | */
25 | public static void main(String[] args) {
26 | if (args.length != 2) {
27 | System.err.println("用法: java AsyncEchoClient ");
28 | System.exit(1);
29 | }
30 |
31 | String hostName = args[0];
32 | int portNumber = Integer.parseInt(args[1]);
33 |
34 | AsynchronousSocketChannel socketChannel = null;
35 | try {
36 | socketChannel = AsynchronousSocketChannel.open();
37 | socketChannel.connect(new InetSocketAddress(hostName, portNumber));
38 | } catch (IOException e) {
39 | System.err.println("AsyncEchoClient异常: " + e.getMessage());
40 | System.exit(1);
41 | }
42 |
43 | ByteBuffer writeBuffer = ByteBuffer.allocate(32);
44 | ByteBuffer readBuffer = ByteBuffer.allocate(32);
45 |
46 | try (BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in))) {
47 | String userInput;
48 | while ((userInput = stdIn.readLine()) != null) {
49 | writeBuffer.put(userInput.getBytes());
50 | writeBuffer.flip();
51 | writeBuffer.rewind();
52 |
53 | // 写消息到管道
54 | socketChannel.write(writeBuffer);
55 |
56 | // 管道读消息
57 | socketChannel.read(readBuffer);
58 |
59 | // 清理缓冲区
60 | writeBuffer.clear();
61 | readBuffer.clear();
62 | System.out.println("echo: " + userInput);
63 | }
64 | } catch (UnknownHostException e) {
65 | System.err.println("不明主机,主机名为: " + hostName);
66 | System.exit(1);
67 | } catch (IOException e) {
68 | System.err.println("不能从主机中获取I/O,主机名为:" + hostName);
69 | System.exit(1);
70 | }
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/java/demo/buffer/ByteBufferDemo.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Welcome to https://waylau.com
3 | */
4 | package com.waylau.java.demo.buffer;
5 |
6 | import java.nio.ByteBuffer;
7 |
8 | /**
9 | * ByteBuffer Demo.
10 | *
11 | * @since 1.0.0 2019年10月7日
12 | * @author Way Lau
13 | */
14 | public class ByteBufferDemo {
15 |
16 | /**
17 | * @param args
18 | */
19 | public static void main(String[] args) {
20 | // 创建一个缓冲区
21 | ByteBuffer buffer = ByteBuffer.allocate(10);
22 | System.out.println("------------初始时缓冲区------------");
23 | printBuffer(buffer);
24 |
25 | // 添加一些数据到缓冲区中
26 | System.out.println("------------添加数据到缓冲区------------");
27 |
28 | String s = "love";
29 | buffer.put(s.getBytes());
30 | printBuffer(buffer);
31 |
32 | // 切换成读模式
33 | System.out.println("------------执行flip切换到读取模式------------");
34 | buffer.flip();
35 | printBuffer(buffer);
36 |
37 | // 读取数据
38 | System.out.println("------------读取数据------------");
39 |
40 | // 创建一个limit()大小的字节数组(因为就只有limit这么多个数据可读)
41 | byte[] bytes = new byte[buffer.limit()];
42 |
43 | // 将读取的数据装进我们的字节数组中
44 | buffer.get(bytes);
45 | printBuffer(buffer);
46 |
47 | // 执行compact
48 | System.out.println("------------执行compact------------");
49 | buffer.compact();
50 | printBuffer(buffer);
51 |
52 | // 执行clear
53 | System.out.println("------------执行clear清空缓冲区------------");
54 | buffer.clear();
55 | printBuffer(buffer);
56 |
57 | }
58 |
59 | /**
60 | * 打印出ByteBuffer的信息
61 | *
62 | * @param buffer
63 | */
64 | private static void printBuffer(ByteBuffer buffer) {
65 | System.out.println("mark:" + buffer.mark());
66 | System.out.println("position:" + buffer.position());
67 | System.out.println("limit:" + buffer.limit());
68 | System.out.println("capacity:" + buffer.capacity());
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/java/demo/concurrent/ThreadPoolExecutorDemo.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Welcome to https://waylau.com
3 | */
4 | package com.waylau.java.demo.concurrent;
5 |
6 | import java.util.concurrent.BlockingQueue;
7 | import java.util.concurrent.ExecutorService;
8 | import java.util.concurrent.LinkedBlockingQueue;
9 | import java.util.concurrent.ThreadPoolExecutor;
10 | import java.util.concurrent.TimeUnit;
11 |
12 | /**
13 | * ThreadPoolExecutor Demo.
14 | *
15 | * @since 1.0.0 2019年11月7日
16 | * @author Way Lau
17 | */
18 | public class ThreadPoolExecutorDemo {
19 |
20 | public static void main(String[] args) {
21 |
22 | // 队列
23 | BlockingQueue workQueue = new LinkedBlockingQueue<>(10);
24 |
25 | // 初始化线程池执行器
26 | ExecutorService pool = new ThreadPoolExecutor(2, 2, 4000, TimeUnit.MILLISECONDS, workQueue);
27 |
28 | for (int i = 0; i < 3; i++) {
29 |
30 | // 提交任务
31 | pool.submit(new MyTask());
32 | }
33 | }
34 |
35 | }
36 |
37 | class MyTask implements Runnable {
38 |
39 | public void run() {
40 | System.out.println(Thread.currentThread().getName() + " is working");
41 | try {
42 | // 模拟一段耗时工作
43 | TimeUnit.SECONDS.sleep(3);
44 | } catch (InterruptedException e) {
45 | e.printStackTrace();
46 | }
47 |
48 | System.out.println(Thread.currentThread().getName() + " done");
49 | }
50 | }
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/java/demo/net/BlockingEchoClient.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Welcome to https://waylau.com
3 | */
4 | package com.waylau.java.demo.net;
5 |
6 | import java.io.BufferedReader;
7 | import java.io.IOException;
8 | import java.io.InputStreamReader;
9 | import java.io.PrintWriter;
10 | import java.net.Socket;
11 | import java.net.UnknownHostException;
12 |
13 | /**
14 | * Blocking Echo Client.
15 | *
16 | * @since 1.0.0 2019年9月28日
17 | * @author Way Lau
18 | */
19 | public class BlockingEchoClient {
20 |
21 | /**
22 | * @param args
23 | */
24 | public static void main(String[] args) {
25 | if (args.length != 2) {
26 | System.err.println(
27 | "用法: java BlockingEchoClient ");
28 | System.exit(1);
29 | }
30 |
31 | String hostName = args[0];
32 | int portNumber = Integer.parseInt(args[1]);
33 |
34 | try (
35 | Socket echoSocket = new Socket(hostName, portNumber);
36 | PrintWriter out =
37 | new PrintWriter(echoSocket.getOutputStream(), true);
38 | BufferedReader in =
39 | new BufferedReader(
40 | new InputStreamReader(echoSocket.getInputStream()));
41 | BufferedReader stdIn =
42 | new BufferedReader(
43 | new InputStreamReader(System.in))
44 | ) {
45 | String userInput;
46 | while ((userInput = stdIn.readLine()) != null) {
47 | out.println(userInput);
48 | System.out.println("echo: " + in.readLine());
49 | }
50 | } catch (UnknownHostException e) {
51 | System.err.println("不明主机,主机名为: " + hostName);
52 | System.exit(1);
53 | } catch (IOException e) {
54 | System.err.println("不能从主机中获取I/O,主机名为:" +
55 | hostName);
56 | System.exit(1);
57 | }
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/java/demo/net/BlockingEchoServer.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Welcome to https://waylau.com
3 | */
4 | package com.waylau.java.demo.net;
5 |
6 | import java.io.BufferedReader;
7 | import java.io.IOException;
8 | import java.io.InputStreamReader;
9 | import java.io.PrintWriter;
10 | import java.net.ServerSocket;
11 | import java.net.Socket;
12 |
13 | /**
14 | * Blocking Echo Server.
15 | *
16 | * @since 1.0.0 2019年9月28日
17 | * @author Way Lau
18 | */
19 | public class BlockingEchoServer {
20 |
21 | public static int DEFAULT_PORT = 7;
22 |
23 | /**
24 | * @param args
25 | */
26 | public static void main(String[] args) {
27 |
28 | int port;
29 |
30 | try {
31 | port = Integer.parseInt(args[0]);
32 | } catch (RuntimeException ex) {
33 | port = DEFAULT_PORT;
34 | }
35 |
36 | ServerSocket serverSocket = null;
37 | try {
38 | // 服务器监听
39 | serverSocket = new ServerSocket(port);
40 | System.out.println(
41 | "BlockingEchoServer已启动,端口:" + port);
42 |
43 | } catch (IOException e) {
44 | System.out.println(
45 | "BlockingEchoServer启动异常,端口:" + port);
46 | System.out.println(e.getMessage());
47 | }
48 |
49 | // Java 7 try-with-resource语句
50 | try (
51 | // 接受客户端建立链接,生成Socket实例
52 | Socket clientSocket = serverSocket.accept();
53 | PrintWriter out =
54 | new PrintWriter(clientSocket.getOutputStream(), true);
55 |
56 | // 接收客户端的信息
57 | BufferedReader in =
58 | new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));) {
59 | String inputLine;
60 | while ((inputLine = in.readLine()) != null) {
61 |
62 | // 发送信息给客户端
63 | out.println(inputLine);
64 | System.out.println(
65 | "BlockingEchoServer -> " + clientSocket.getRemoteSocketAddress() + ":" + inputLine);
66 | }
67 | } catch (IOException e) {
68 | System.out.println(
69 | "BlockingEchoServer异常!" + e.getMessage());
70 | }
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/java/demo/nio/NonBlockingEchoClient.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Welcome to https://waylau.com
3 | */
4 | package com.waylau.java.demo.nio;
5 |
6 | import java.io.BufferedReader;
7 | import java.io.IOException;
8 | import java.io.InputStreamReader;
9 | import java.net.InetSocketAddress;
10 | import java.net.UnknownHostException;
11 | import java.nio.ByteBuffer;
12 | import java.nio.channels.SocketChannel;
13 |
14 | /**
15 | * Non Blocking Echo Client.
16 | *
17 | * @since 1.0.0 2019年9月28日
18 | * @author Way Lau
19 | */
20 | public class NonBlockingEchoClient {
21 |
22 | /**
23 | * @param args
24 | */
25 | public static void main(String[] args) {
26 | if (args.length != 2) {
27 | System.err.println("用法: java NonBlockingEchoClient ");
28 | System.exit(1);
29 | }
30 |
31 | String hostName = args[0];
32 | int portNumber = Integer.parseInt(args[1]);
33 |
34 | SocketChannel socketChannel = null;
35 | try {
36 | socketChannel = SocketChannel.open();
37 | socketChannel.connect(new InetSocketAddress(hostName, portNumber));
38 | } catch (IOException e) {
39 | System.err.println("NonBlockingEchoClient异常: " + e.getMessage());
40 | System.exit(1);
41 | }
42 |
43 | ByteBuffer writeBuffer = ByteBuffer.allocate(32);
44 | ByteBuffer readBuffer = ByteBuffer.allocate(32);
45 |
46 | try (BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in))) {
47 | String userInput;
48 | while ((userInput = stdIn.readLine()) != null) {
49 | writeBuffer.put(userInput.getBytes());
50 | writeBuffer.flip();
51 | writeBuffer.rewind();
52 |
53 | // 写消息到管道
54 | socketChannel.write(writeBuffer);
55 |
56 | // 管道读消息
57 | socketChannel.read(readBuffer);
58 |
59 | // 清理缓冲区
60 | writeBuffer.clear();
61 | readBuffer.clear();
62 | System.out.println("echo: " + userInput);
63 | }
64 | } catch (UnknownHostException e) {
65 | System.err.println("不明主机,主机名为: " + hostName);
66 | System.exit(1);
67 | } catch (IOException e) {
68 | System.err.println("不能从主机中获取I/O,主机名为:" + hostName);
69 | System.exit(1);
70 | }
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/java/demo/reactor/basic/Acceptor.java:
--------------------------------------------------------------------------------
1 | package com.waylau.java.demo.reactor.basic;
2 |
3 | import java.io.IOException;
4 | import java.nio.channels.Selector;
5 | import java.nio.channels.ServerSocketChannel;
6 | import java.nio.channels.SocketChannel;
7 |
8 |
9 | /**
10 | * Acceptor
11 | *
12 | * @since 1.0.0 2019年11月14日
13 | * @author Way Lau
14 | */
15 | public class Acceptor implements Runnable {
16 |
17 | private final Selector selector;
18 |
19 | private final ServerSocketChannel serverSocketChannel;
20 |
21 | Acceptor(ServerSocketChannel serverSocketChannel, Selector selector) {
22 | this.serverSocketChannel = serverSocketChannel;
23 | this.selector = selector;
24 | }
25 |
26 | @Override
27 | public void run() {
28 | SocketChannel socketChannel;
29 | try {
30 | socketChannel = serverSocketChannel.accept();
31 | if (socketChannel != null) {
32 | System.out.println(String.format("accpet %s", socketChannel.getRemoteAddress()));
33 |
34 | // 这里把客户端通道传给Handler,Handler负责接下来的事件处理
35 | new AsyncHandler(socketChannel, selector);
36 | }
37 | } catch (IOException e) {
38 | e.printStackTrace();
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/java/demo/reactor/basic/BasicReactorDemo.java:
--------------------------------------------------------------------------------
1 | package com.waylau.java.demo.reactor.basic;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * Basic Reactor Demo
7 | *
8 | * @since 1.0.0 2019年11月14日
9 | * @author Way Lau
10 | */
11 | public class BasicReactorDemo {
12 |
13 | public static void main(String[] args) throws IOException {
14 | new Thread(new Reactor(2333)).start();
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/java/demo/reactor/basic/Reactor.java:
--------------------------------------------------------------------------------
1 | package com.waylau.java.demo.reactor.basic;
2 |
3 | import java.io.IOException;
4 | import java.net.InetSocketAddress;
5 | import java.nio.channels.SelectionKey;
6 | import java.nio.channels.Selector;
7 | import java.nio.channels.ServerSocketChannel;
8 | import java.util.Iterator;
9 | import java.util.Set;
10 |
11 | /**
12 | * Reactor
13 | *
14 | * @since 1.0.0 2019年11月14日
15 | * @author Way Lau
16 | */
17 | public class Reactor implements Runnable {
18 |
19 | private final Selector selector;
20 | private final ServerSocketChannel serverSocketChannel;
21 |
22 | public Reactor(int port) throws IOException { // Reactor初始化
23 | selector = Selector.open(); // 打开一个Selector
24 | serverSocketChannel = ServerSocketChannel.open(); // 建立一个Server端通道
25 | serverSocketChannel.socket().bind(new InetSocketAddress(port)); // 绑定服务端口
26 | serverSocketChannel.configureBlocking(false); // selector模式下,所有通道必须是非阻塞的
27 |
28 | // Reactor是入口,最初给一个channel注册上去的事件都是accept
29 | SelectionKey sk = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
30 |
31 | // 附加回调对象Acceptor
32 | sk.attach(new Acceptor(serverSocketChannel, selector));
33 | }
34 |
35 | @Override
36 | public void run() {
37 | try {
38 | while (!Thread.interrupted()) {
39 | // 就绪事件到达之前,阻塞
40 | selector.select();
41 |
42 | // 拿到本次select获取的就绪事件
43 | Set selected = selector.selectedKeys();
44 | Iterator it = selected.iterator();
45 | while (it.hasNext()) {
46 | // 任务分发
47 | dispatch((SelectionKey) (it.next()));
48 | }
49 | selected.clear();
50 | }
51 | } catch (IOException e) {
52 | e.printStackTrace();
53 | }
54 | }
55 |
56 | void dispatch(SelectionKey k) {
57 | // 附带对象为Acceptor
58 | Runnable r = (Runnable) (k.attachment());
59 |
60 | if (r != null) {
61 | long s = System.currentTimeMillis();
62 | r.run();
63 | long e = System.currentTimeMillis() - s;
64 | System.out.println("---------cost time: " + e);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/java/demo/reactor/client/ClientDemo.java:
--------------------------------------------------------------------------------
1 | package com.waylau.java.demo.reactor.client;
2 |
3 | /**
4 | * Client Demo
5 | *
6 | * @since 1.0.0 2019年11月14日
7 | * @author Way Lau
8 | */
9 | public class ClientDemo {
10 |
11 | public static void main(String[] args) {
12 | new Thread(new NIOClient("127.0.0.1", 2333)).start();
13 | new Thread(new NIOClient("127.0.0.1", 2333)).start();
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/java/demo/reactor/client/Connector.java:
--------------------------------------------------------------------------------
1 | package com.waylau.java.demo.reactor.client;
2 |
3 | import java.io.IOException;
4 | import java.nio.channels.Selector;
5 | import java.nio.channels.SocketChannel;
6 |
7 | /**
8 | * Connector
9 | *
10 | * @since 1.0.0 2019年11月14日
11 | * @author Way Lau
12 | */
13 | public class Connector implements Runnable {
14 |
15 | private final Selector selector;
16 |
17 | private final SocketChannel socketChannel;
18 |
19 | Connector(SocketChannel socketChannel, Selector selector) {
20 | this.socketChannel = socketChannel;
21 | this.selector = selector;
22 | }
23 |
24 | @Override
25 | public void run() {
26 | try {
27 | if (socketChannel.finishConnect()) {
28 | // 这里连接完成(与服务端的三次握手完成)
29 | System.out.println(String.format("connected to %s", socketChannel.getRemoteAddress()));
30 |
31 | // 连接建立完成后,接下来的动作交给Handler去处理(读写等)
32 | new Handler(socketChannel, selector);
33 | }
34 | } catch (IOException e) {
35 | e.printStackTrace();
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/java/demo/reactor/client/NIOClient.java:
--------------------------------------------------------------------------------
1 | package com.waylau.java.demo.reactor.client;
2 |
3 | import java.io.IOException;
4 | import java.net.InetSocketAddress;
5 | import java.nio.channels.SelectionKey;
6 | import java.nio.channels.Selector;
7 | import java.nio.channels.SocketChannel;
8 | import java.util.Iterator;
9 | import java.util.Set;
10 |
11 | /**
12 | * NIO Client
13 | *
14 | * @since 1.0.0 2019年11月14日
15 | * @author Way Lau
16 | */
17 | public class NIOClient implements Runnable {
18 |
19 | private Selector selector;
20 |
21 | private SocketChannel socketChannel;
22 |
23 | NIOClient(String ip, int port) {
24 | try {
25 | selector = Selector.open(); //打开一个Selector
26 | socketChannel = SocketChannel.open();
27 | socketChannel.configureBlocking(false); //设置为非阻塞模式
28 | socketChannel.connect(new InetSocketAddress(ip, port)); //连接服务
29 |
30 | //入口,最初给一个客户端channel注册上去的事件都是连接事件
31 | SelectionKey sk = socketChannel.register(selector, SelectionKey.OP_CONNECT);
32 |
33 | //附加处理类,第一次初始化放的是连接就绪处理类
34 | sk.attach(new Connector(socketChannel, selector));
35 | } catch (IOException e) {
36 | e.printStackTrace();
37 | }
38 | }
39 |
40 | @Override
41 | public void run() {
42 | try {
43 | while (!Thread.interrupted()) {
44 | //就绪事件到达之前,阻塞
45 | selector.select();
46 |
47 | //拿到本次select获取的就绪事件
48 | Set selected = selector.selectedKeys();
49 | Iterator it = selected.iterator();
50 | while (it.hasNext()) {
51 | //这里进行任务分发
52 | dispatch((SelectionKey) (it.next()));
53 | }
54 | selected.clear();
55 | }
56 | } catch (IOException e) {
57 | e.printStackTrace();
58 | }
59 | }
60 |
61 | void dispatch(SelectionKey k) {
62 | // 附带对象为Connector(
63 | Runnable r = (Runnable) (k.attachment());
64 |
65 | //调用之前注册的回调对象
66 | if (r != null) {
67 | r.run();
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/java/demo/reactor/mainsub/Acceptor.java:
--------------------------------------------------------------------------------
1 | package com.waylau.java.demo.reactor.mainsub;
2 |
3 | import java.io.IOException;
4 | import java.nio.channels.SelectionKey;
5 | import java.nio.channels.Selector;
6 | import java.nio.channels.ServerSocketChannel;
7 | import java.nio.channels.SocketChannel;
8 |
9 | /**
10 | * Acceptor
11 | *
12 | * @since 1.0.0 2019年11月14日
13 | * @author Way Lau
14 | */
15 | public class Acceptor implements Runnable {
16 |
17 | private final ServerSocketChannel serverSocketChannel;
18 |
19 | private final int coreNum = Runtime.getRuntime().availableProcessors(); // CPU核心数
20 |
21 | private final Selector[] selectors = new Selector[coreNum]; // 创建selector给SubReactor使用
22 |
23 | private int next = 0; // 轮询使用subReactor的下标索引
24 |
25 | private SubReactor[] reactors = new SubReactor[coreNum]; // subReactor
26 |
27 | private Thread[] threads = new Thread[coreNum]; // subReactor的处理线程
28 |
29 | Acceptor(ServerSocketChannel serverSocketChannel) throws IOException {
30 | this.serverSocketChannel = serverSocketChannel;
31 | // 初始化
32 | for (int i = 0; i < coreNum; i++) {
33 | selectors[i] = Selector.open();
34 | reactors[i] = new SubReactor(selectors[i], i); // 初始化sub reactor
35 | threads[i] = new Thread(reactors[i]); // 初始化运行sub reactor的线程
36 | threads[i].start(); // 启动(启动后的执行参考SubReactor里的run方法)
37 | }
38 | }
39 |
40 | @Override
41 | public void run() {
42 | SocketChannel socketChannel;
43 | try {
44 | socketChannel = serverSocketChannel.accept(); // 连接
45 | if (socketChannel != null) {
46 | System.out.println(String.format("accpet %s", socketChannel.getRemoteAddress()));
47 | socketChannel.configureBlocking(false);
48 |
49 | // 注意一个selector在select时是无法注册新事件的,因此这里要先暂停下select方法触发的程序段,
50 | // 下面的weakup和这里的setRestart都是做这个事情的,具体参考SubReactor里的run方法
51 | reactors[next].registering(true);
52 | selectors[next].wakeup(); // 使一个阻塞住的selector操作立即返回
53 | SelectionKey selectionKey =
54 | socketChannel.register(selectors[next], SelectionKey.OP_READ); // 注册一个读事件
55 | selectors[next].wakeup(); // 使一个阻塞住的selector操作立即返回
56 |
57 | // 本次事件注册完成后,需要再次触发select的执行,
58 | // 因此这里Restart要在设置回false(具体参考SubReactor里的run方法)
59 | reactors[next].registering(false);
60 |
61 | // 绑定Handler
62 | selectionKey.attach(new AsyncHandler(socketChannel, selectors[next], next));
63 | if (++next == selectors.length) {
64 | next = 0; // 越界后重新分配
65 | }
66 | }
67 | } catch (IOException e) {
68 | e.printStackTrace();
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/java/demo/reactor/mainsub/MainSubReactorDemo.java:
--------------------------------------------------------------------------------
1 | package com.waylau.java.demo.reactor.mainsub;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * Main Sub Reactor Demo
7 | *
8 | * @since 1.0.0 2019年11月14日
9 | * @author Way Lau
10 | */
11 | public class MainSubReactorDemo {
12 |
13 | public static void main(String[] args) throws IOException {
14 | new Thread(new Reactor(2333)).start();
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/java/demo/reactor/mainsub/Reactor.java:
--------------------------------------------------------------------------------
1 | package com.waylau.java.demo.reactor.mainsub;
2 |
3 | import java.io.IOException;
4 | import java.net.InetSocketAddress;
5 | import java.nio.channels.SelectionKey;
6 | import java.nio.channels.Selector;
7 | import java.nio.channels.ServerSocketChannel;
8 | import java.util.Iterator;
9 | import java.util.Set;
10 |
11 | /**
12 | * Reactor
13 | *
14 | * @since 1.0.0 2019年11月14日
15 | * @author Way Lau
16 | */
17 | public class Reactor implements Runnable {
18 |
19 | private final Selector selector;
20 | private final ServerSocketChannel serverSocketChannel;
21 |
22 | public Reactor(int port) throws IOException {
23 | selector = Selector.open(); // 打开一个Selector
24 | serverSocketChannel = ServerSocketChannel.open(); // 建立一个Server端通道
25 | serverSocketChannel.socket().bind(new InetSocketAddress(port)); // 绑定服务端口
26 | serverSocketChannel.configureBlocking(false); // selector模式下,所有通道必须是非阻塞的
27 |
28 | // Reactor是入口,最初给一个channel注册上去的事件都是accept
29 | SelectionKey sk = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
30 |
31 | // 绑定Acceptor处理类
32 | sk.attach(new Acceptor(serverSocketChannel));
33 | }
34 |
35 | @Override
36 | public void run() {
37 | try {
38 | while (!Thread.interrupted()) {
39 | int count = selector.select(); // 就绪事件到达之前,阻塞
40 | if (count == 0) {
41 | continue;
42 | }
43 | Set selected = selector.selectedKeys(); // 拿到本次select获取的就绪事件
44 | Iterator it = selected.iterator();
45 | while (it.hasNext()) {
46 | // 这里进行任务分发
47 | dispatch((SelectionKey) (it.next()));
48 | }
49 | selected.clear();
50 | }
51 | } catch (IOException e) {
52 | e.printStackTrace();
53 | }
54 | }
55 |
56 | void dispatch(SelectionKey k) {
57 | // 附带对象为Acceptor
58 | Runnable r = (Runnable) (k.attachment());
59 |
60 | // 调用之前注册的回调对象
61 | if (r != null) {
62 | r.run();
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/java/demo/reactor/mainsub/SubReactor.java:
--------------------------------------------------------------------------------
1 | package com.waylau.java.demo.reactor.mainsub;
2 |
3 | import java.io.IOException;
4 | import java.nio.channels.SelectionKey;
5 | import java.nio.channels.Selector;
6 | import java.util.Iterator;
7 | import java.util.Set;
8 |
9 | /**
10 | * SubReactor
11 | *
12 | * @since 1.0.0 2019年11月14日
13 | * @author Way Lau
14 | */
15 | public class SubReactor implements Runnable {
16 | private final Selector selector;
17 | private boolean register = false; // 注册开关表示
18 | private int num; // 序号,也就是Acceptor初始化SubReactor时的下标
19 |
20 | SubReactor(Selector selector, int num) {
21 | this.selector = selector;
22 | this.num = num;
23 | }
24 |
25 | @Override
26 | public void run() {
27 | while (!Thread.interrupted()) {
28 | System.out.println(String.format("NO %d SubReactor waitting for register...", num));
29 | while (!Thread.interrupted() && !register) {
30 | try {
31 | if (selector.select() == 0) {
32 | continue;
33 | }
34 | } catch (IOException e) {
35 | e.printStackTrace();
36 | }
37 | Set selectedKeys = selector.selectedKeys();
38 | Iterator it = selectedKeys.iterator();
39 | while (it.hasNext()) {
40 | dispatch(it.next());
41 | it.remove();
42 | }
43 | }
44 | }
45 | }
46 |
47 | private void dispatch(SelectionKey key) {
48 | Runnable r = (Runnable) (key.attachment());
49 | if (r != null) {
50 | r.run();
51 | }
52 | }
53 |
54 | void registering(boolean register) {
55 | this.register = register;
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/netty/TcpClient.java:
--------------------------------------------------------------------------------
1 | package com.waylau.netty;
2 |
3 | import java.io.IOException;
4 | import java.io.OutputStream;
5 | import java.net.Socket;
6 |
7 | /**
8 | * TCP Client.
9 | *
10 | * @since 1.0.0 2019年12月12日
11 | * @author Way Lau
12 | */
13 | public class TcpClient {
14 |
15 | public static void main(String[] args) throws IOException {
16 | Socket socket = null;
17 | OutputStream out = null;
18 |
19 | try {
20 |
21 | socket = new Socket("localhost", 8023);
22 | out = socket.getOutputStream();
23 |
24 | // 请求服务器
25 | String lines = "床前明月光\r\n疑是地上霜\r\n举头望明月\r\n低头思故乡\r\n";
26 | byte[] outputBytes = lines.getBytes("UTF-8");
27 | out.write(outputBytes);
28 | out.flush();
29 |
30 | } finally {
31 | // 关闭连接
32 | out.close();
33 | socket.close();
34 | }
35 |
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/netty/demo/buffer/ByteBufCompositeBufferDemo.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Welcome to https://waylau.com
3 | */
4 | package com.waylau.netty.demo.buffer;
5 |
6 | import io.netty.buffer.ByteBuf;
7 | import io.netty.buffer.CompositeByteBuf;
8 | import io.netty.buffer.Unpooled;
9 |
10 | /**
11 | * ByteBuf with Composite Buffer Mode Demo.
12 | *
13 | * @since 1.0.0 2019年10月8日
14 | * @author Way Lau
15 | */
16 | public class ByteBufCompositeBufferDemo {
17 |
18 | /**
19 | * @param args
20 | */
21 | public static void main(String[] args) {
22 |
23 | // 创建一个堆缓冲区
24 | ByteBuf heapBuf = Unpooled.buffer(3);
25 | String way = "way";
26 | heapBuf.writeBytes(way.getBytes());
27 |
28 | // 创建一个直接缓冲区
29 | ByteBuf directBuf = Unpooled.directBuffer(3);
30 | String lau = "lau";
31 | directBuf.writeBytes(lau.getBytes());
32 |
33 | // 创建一个复合缓冲区
34 | CompositeByteBuf compositeBuffer = Unpooled.compositeBuffer(10);
35 | compositeBuffer.addComponents(heapBuf, directBuf); // 将缓冲区添加到符合缓冲区
36 |
37 | // 检查是否是支撑数组.
38 | // 不是支撑数组,则为复合缓冲区
39 | if (!compositeBuffer.hasArray()) {
40 |
41 | for (ByteBuf buffer : compositeBuffer) {
42 | // 计算第一个字节的偏移量
43 | int offset = buffer.readerIndex();
44 |
45 | // 可读字节数
46 | int length = buffer.readableBytes();
47 |
48 | // 获取字节内容
49 | byte[] array = new byte[length];
50 | buffer.getBytes(offset, array);
51 |
52 | printBuffer(array, offset, length);
53 | }
54 |
55 | }
56 | }
57 |
58 | /**
59 | * 打印出Buffer的信息
60 | *
61 | * @param buffer
62 | */
63 | private static void printBuffer(byte[] array, int offset, int len) {
64 | System.out.println("array:" + array);
65 | System.out.println("array->String:" + new String(array));
66 | System.out.println("offset:" + offset);
67 | System.out.println("len:" + len);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/netty/demo/buffer/ByteBufDemo.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Welcome to https://waylau.com
3 | */
4 | package com.waylau.netty.demo.buffer;
5 |
6 | import io.netty.buffer.ByteBuf;
7 | import io.netty.buffer.Unpooled;
8 |
9 | /**
10 | * ByteBuf Demo.
11 | *
12 | * @since 1.0.0 2019年10月7日
13 | * @author Way Lau
14 | */
15 | public class ByteBufDemo {
16 |
17 | /**
18 | * @param args
19 | */
20 | public static void main(String[] args) {
21 | // 创建一个缓冲区
22 | ByteBuf buffer = Unpooled.buffer(10);
23 | System.out.println("------------初始时缓冲区------------");
24 | printBuffer(buffer);
25 |
26 | // 添加一些数据到缓冲区中
27 | System.out.println("------------添加数据到缓冲区------------");
28 |
29 | String s = "love";
30 | buffer.writeBytes(s.getBytes());
31 | printBuffer(buffer);
32 |
33 | // 读取数据
34 | System.out.println("------------读取数据------------");
35 |
36 | while (buffer.isReadable()) {
37 | System.out.println(buffer.readByte());
38 | }
39 |
40 | printBuffer(buffer);
41 |
42 | // 执行compact
43 | System.out.println("------------执行discardReadBytes------------");
44 | buffer.discardReadBytes();
45 | printBuffer(buffer);
46 |
47 | // 执行clear
48 | System.out.println("------------执行clear清空缓冲区------------");
49 | buffer.clear();
50 | printBuffer(buffer);
51 |
52 | }
53 |
54 | /**
55 | * 打印出ByteBuf的信息
56 | *
57 | * @param buffer
58 | */
59 | private static void printBuffer(ByteBuf buffer) {
60 | System.out.println("readerIndex:" + buffer.readerIndex());
61 | System.out.println("writerIndex:" + buffer.writerIndex());
62 | System.out.println("capacity:" + buffer.capacity());
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/netty/demo/buffer/ByteBufDirectBufferDemo.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Welcome to https://waylau.com
3 | */
4 | package com.waylau.netty.demo.buffer;
5 |
6 | import io.netty.buffer.ByteBuf;
7 | import io.netty.buffer.Unpooled;
8 |
9 | /**
10 | * ByteBuf with Direct Buffer Mode Demo.
11 | *
12 | * @since 1.0.0 2019年10月7日
13 | * @author Way Lau
14 | */
15 | public class ByteBufDirectBufferDemo {
16 |
17 | /**
18 | * @param args
19 | */
20 | public static void main(String[] args) {
21 |
22 | // 创建一个直接缓冲区
23 | ByteBuf buffer = Unpooled.directBuffer(10);
24 | String s = "waylau";
25 | buffer.writeBytes(s.getBytes());
26 |
27 | // 检查是否是支撑数组.
28 | // 不是支撑数组,则为直接缓冲区
29 | if (!buffer.hasArray()) {
30 |
31 | // 计算第一个字节的偏移量
32 | int offset = buffer.readerIndex();
33 |
34 | // 可读字节数
35 | int length = buffer.readableBytes();
36 |
37 | // 获取字节内容
38 | byte[] array = new byte[length];
39 | buffer.getBytes(offset, array);
40 |
41 | printBuffer(array, offset, length);
42 | }
43 | }
44 |
45 | /**
46 | * 打印出Buffer的信息
47 | *
48 | * @param buffer
49 | */
50 | private static void printBuffer(byte[] array, int offset, int len) {
51 | System.out.println("array:" + array);
52 | System.out.println("array->String:" + new String(array));
53 | System.out.println("offset:" + offset);
54 | System.out.println("len:" + len);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/netty/demo/buffer/ByteBufHeapBufferDemo.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Welcome to https://waylau.com
3 | */
4 | package com.waylau.netty.demo.buffer;
5 |
6 | import io.netty.buffer.ByteBuf;
7 | import io.netty.buffer.Unpooled;
8 |
9 | /**
10 | * ByteBuf with Heap Buffer Mode Demo.
11 | *
12 | * @since 1.0.0 2019年10月7日
13 | * @author Way Lau
14 | */
15 | public class ByteBufHeapBufferDemo {
16 |
17 | /**
18 | * @param args
19 | */
20 | public static void main(String[] args) {
21 |
22 | // 创建一个堆缓冲区
23 | ByteBuf buffer = Unpooled.buffer(10);
24 | String s = "waylau";
25 | buffer.writeBytes(s.getBytes());
26 |
27 | // 检查是否是支撑数组
28 | if (buffer.hasArray()) {
29 |
30 | // 获取支撑数组的引用
31 | byte[] array = buffer.array();
32 |
33 | // 计算第一个字节的偏移量
34 | int offset = buffer.readerIndex() + buffer.arrayOffset();
35 |
36 | // 可读字节数
37 | int length = buffer.readableBytes();
38 | printBuffer(array, offset, length);
39 | }
40 | }
41 |
42 | /**
43 | * 打印出Buffer的信息
44 | *
45 | * @param buffer
46 | */
47 | private static void printBuffer(byte[] array, int offset, int len) {
48 | System.out.println("array:" + array);
49 | System.out.println("array->String:" + new String(array));
50 | System.out.println("offset:" + offset);
51 | System.out.println("len:" + len);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/netty/demo/codec/Msg.java:
--------------------------------------------------------------------------------
1 | package com.waylau.netty.demo.codec;
2 |
3 | /**
4 | * Message.
5 | *
6 | * @since 1.0.0 2019年12月16日
7 | * @author Way Lau
8 | */
9 | public class Msg {
10 |
11 | private MsgHeader msgHeader = new MsgHeader();
12 | private String body;
13 |
14 | public MsgHeader getMsgHeader() {
15 | return msgHeader;
16 | }
17 |
18 | public void setMsgHeader(MsgHeader msgHeader) {
19 | this.msgHeader = msgHeader;
20 | }
21 |
22 | public String getBody() {
23 | return body;
24 | }
25 |
26 | public void setBody(String body) {
27 | this.body = body;
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/netty/demo/codec/MsgHeader.java:
--------------------------------------------------------------------------------
1 | package com.waylau.netty.demo.codec;
2 |
3 | /**
4 | * Message Header.
5 | *
6 | * @since 1.0.0 2019年12月16日
7 | * @author Way Lau
8 | */
9 | public class MsgHeader {
10 | private byte msgType; // 消息类型
11 | private int len; // 长度
12 |
13 | public MsgHeader() {
14 | }
15 |
16 | public MsgHeader(byte msgType, int len) {
17 | this.msgType = msgType;
18 | this.len = len;
19 | }
20 |
21 | public byte getMsgType() {
22 | return msgType;
23 | }
24 |
25 | public void setMsgType(byte msgType) {
26 | this.msgType = msgType;
27 | }
28 |
29 | public int getLen() {
30 | return len;
31 | }
32 |
33 | public void setLen(int len) {
34 | this.len = len;
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/netty/demo/codec/MsgType.java:
--------------------------------------------------------------------------------
1 | package com.waylau.netty.demo.codec;
2 |
3 | /**
4 | * Message Type.
5 | *
6 | * @since 1.0.0 2019年12月16日
7 | * @author Way Lau
8 | */
9 | public enum MsgType {
10 | EMGW_LOGIN_REQ((byte) 0x00),
11 | EMGW_LOGIN_RES((byte) 0x01);
12 |
13 | private byte value;
14 |
15 | public byte getValue() {
16 | return value;
17 | }
18 |
19 | private MsgType(byte value) {
20 | this.value = value;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/netty/demo/codec/MyClient.java:
--------------------------------------------------------------------------------
1 | package com.waylau.netty.demo.codec;
2 |
3 | import java.nio.charset.Charset;
4 |
5 | import io.netty.bootstrap.Bootstrap;
6 | import io.netty.channel.ChannelFuture;
7 | import io.netty.channel.ChannelInitializer;
8 | import io.netty.channel.ChannelOption;
9 | import io.netty.channel.EventLoopGroup;
10 | import io.netty.channel.nio.NioEventLoopGroup;
11 | import io.netty.channel.socket.SocketChannel;
12 | import io.netty.channel.socket.nio.NioSocketChannel;
13 |
14 | /**
15 | * My Client.
16 | *
17 | * @since 1.0.0 2019年12月16日
18 | * @author Way Lau
19 | */
20 | public class MyClient {
21 |
22 | private String host;
23 | private int port;
24 |
25 | public MyClient(String host, int port) {
26 | this.host = host;
27 | this.port = port;
28 | }
29 |
30 | public void run() throws InterruptedException {
31 |
32 | EventLoopGroup workerGroup = new NioEventLoopGroup();
33 |
34 | try {
35 | Bootstrap b = new Bootstrap();
36 | b.group(workerGroup);
37 | b.channel(NioSocketChannel.class);
38 | b.option(ChannelOption.SO_KEEPALIVE, true);
39 | b.handler(new ChannelInitializer() {
40 | @Override
41 | public void initChannel(SocketChannel ch) throws Exception {
42 | ch.pipeline().addLast("codec", new MyCodec());
43 | ch.pipeline().addLast(new MyClientHandler());
44 |
45 | }
46 | });
47 |
48 | // 启动客户端
49 | ChannelFuture f = b.connect(host, port).sync();
50 |
51 | while (true) {
52 |
53 | // 发送消息给服务器
54 | Msg msg = new Msg();
55 | MsgHeader msgHeader = new MsgHeader();
56 | msgHeader.setMsgType(MsgType.EMGW_LOGIN_REQ.getValue());
57 | String body = "床前明月光,疑是地上霜。举头望明月,低头思故乡。";
58 |
59 | byte[] bodyBytes = body.getBytes(Charset.forName("utf-8"));
60 | int bodySize = bodyBytes.length;
61 | msgHeader.setLen(bodySize);
62 | msg.setMsgHeader(msgHeader);
63 | msg.setBody(body);
64 |
65 | f.channel().writeAndFlush(msg);
66 | Thread.sleep(2000);
67 | }
68 | } finally {
69 | workerGroup.shutdownGracefully();
70 | }
71 | }
72 |
73 | public static void main(String[] args) throws InterruptedException {
74 | new MyClient("localhost", 8082).run();
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/netty4-demos/src/main/java/com/waylau/netty/demo/codec/MyClientHandler.java:
--------------------------------------------------------------------------------
1 | package com.waylau.netty.demo.codec;
2 |
3 | import io.netty.channel.Channel;
4 | import io.netty.channel.ChannelHandlerContext;
5 | import io.netty.channel.SimpleChannelInboundHandler;
6 |
7 | /**
8 | * My ClientHandler.
9 | *
10 | * @since 1.0.0 2019年12月16日
11 | * @author Way Lau
12 | */
13 | public class MyClientHandler extends SimpleChannelInboundHandler