├── .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 { 14 | 15 | @Override 16 | protected void channelRead0(ChannelHandlerContext ctx, Object obj) throws Exception { 17 | Channel incoming = ctx.channel(); 18 | 19 | if (obj instanceof Msg) { 20 | Msg msg = (Msg) obj; 21 | System.out.println("Server->Client:" + incoming.remoteAddress() + msg.getBody()); 22 | } else { 23 | System.out.println("Server->Client:" + incoming.remoteAddress() + obj.toString()); 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/MyCodec.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to https://waylau.com 3 | */ 4 | package com.waylau.netty.demo.codec; 5 | 6 | import io.netty.channel.CombinedChannelDuplexHandler; 7 | 8 | /** 9 | * My Codec. 10 | * 11 | * @since 1.0.0 2019年12月17日 12 | * @author Way Lau 13 | */ 14 | public class MyCodec extends CombinedChannelDuplexHandler { 15 | public MyCodec() { 16 | super(new MyDecoder(), new MyEncoder()); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/MyDecoder.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.codec; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.codec.LengthFieldBasedFrameDecoder; 6 | 7 | /** 8 | * My Decoder. 9 | * 10 | * @since 1.0.0 2019年12月16日 11 | * @author Way Lau 12 | */ 13 | public class MyDecoder extends LengthFieldBasedFrameDecoder { 14 | 15 | private static final int MAX_FRAME_LENGTH = 1024 * 1024; 16 | private static final int LENGTH_FIELD_LENGTH = 1; 17 | private static final int LENGTH_FIELD_OFFSET = 4; 18 | private static final int LENGTH_ADJUSTMENT = 0; 19 | private static final int INITIAL_BYTES_TO_STRIP = 0; 20 | 21 | private static final int HEADER_SIZE = 5; 22 | private byte msgType; // 消息类型 23 | private int len; // 长度 24 | 25 | public MyDecoder() { 26 | super(MAX_FRAME_LENGTH, 27 | LENGTH_FIELD_OFFSET, LENGTH_FIELD_LENGTH, 28 | LENGTH_ADJUSTMENT, INITIAL_BYTES_TO_STRIP); 29 | } 30 | 31 | @Override 32 | protected Msg decode(ChannelHandlerContext ctx, ByteBuf in2) throws Exception { 33 | ByteBuf in = (ByteBuf) super.decode(ctx, in2); 34 | if (in == null) { 35 | return null; 36 | } 37 | 38 | // 校验头长度 39 | if (in.readableBytes() < HEADER_SIZE) { 40 | return null; 41 | } 42 | 43 | msgType = in.readByte(); 44 | len = in.readInt(); 45 | 46 | // 校验消息体长度 47 | if (in.readableBytes() < len) { 48 | return null; 49 | } 50 | 51 | ByteBuf buf = in.readBytes(len); 52 | byte[] req = new byte[buf.readableBytes()]; 53 | buf.readBytes(req); 54 | String body = new String(req, "UTF-8"); 55 | 56 | // ByteBuf转为Msg类型 57 | Msg msg = new Msg(); 58 | MsgHeader msgHeader = new MsgHeader(msgType, len); 59 | msg.setBody(body); 60 | msg.setMsgHeader(msgHeader); 61 | return msg; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/MyEncoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.netty.demo.codec; 5 | 6 | import java.nio.charset.Charset; 7 | 8 | import io.netty.buffer.ByteBuf; 9 | import io.netty.channel.ChannelHandlerContext; 10 | import io.netty.handler.codec.MessageToByteEncoder; 11 | 12 | /** 13 | * My Encoder. 14 | * 15 | * @since 1.0.0 2019年12月16日 16 | * @author Way Lau 17 | */ 18 | public class MyEncoder extends MessageToByteEncoder { 19 | 20 | @Override 21 | protected void encode(ChannelHandlerContext ctx, Msg msg, ByteBuf out) throws Exception { 22 | if (msg == null | msg.getMsgHeader() == null) { 23 | throw new Exception("The encode message is null"); 24 | } 25 | 26 | // 获取消息头 27 | MsgHeader header = msg.getMsgHeader(); 28 | 29 | // 获取消息体 30 | String body = msg.getBody(); 31 | byte[] bodyBytes = body.getBytes(Charset.forName("utf-8")); 32 | 33 | // 计算消息体的长度 34 | int bodySize = bodyBytes.length; 35 | 36 | System.out.printf("MyEncoder header: %s, body: %s", header.getMsgType(), body); 37 | 38 | out.writeByte(MsgType.EMGW_LOGIN_RES.getValue()); 39 | out.writeInt(bodySize); 40 | out.writeBytes(bodyBytes); 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/MyServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.codec; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelOption; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.channel.socket.nio.NioServerSocketChannel; 11 | import io.netty.handler.logging.LogLevel; 12 | import io.netty.handler.logging.LoggingHandler; 13 | 14 | /** 15 | * My Server. 16 | * 17 | * @since 1.0.0 2019年12月16日 18 | * @author Way Lau 19 | */ 20 | public class MyServer { 21 | 22 | private int port; 23 | 24 | public MyServer(int port) { 25 | this.port = port; 26 | } 27 | 28 | public void run() throws Exception { 29 | EventLoopGroup bossGroup = new NioEventLoopGroup(); 30 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 31 | try { 32 | ServerBootstrap b = new ServerBootstrap(); 33 | b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) 34 | .childHandler(new ChannelInitializer() { 35 | @Override 36 | public void initChannel(SocketChannel ch) throws Exception { 37 | // 添加日志 38 | ch.pipeline().addLast("logging", new LoggingHandler(LogLevel.INFO)); 39 | 40 | // 添加编解码器 41 | ch.pipeline().addLast("codec", new MyCodec()); 42 | ch.pipeline().addLast(new MyServerHandler()); 43 | } 44 | }).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true); 45 | 46 | ChannelFuture f = b.bind(port).sync(); 47 | 48 | System.out.println("Server start listen at " + port); 49 | 50 | f.channel().closeFuture().sync(); 51 | 52 | } finally { 53 | workerGroup.shutdownGracefully(); 54 | bossGroup.shutdownGracefully(); 55 | } 56 | } 57 | 58 | public static void main(String[] args) throws Exception { 59 | int port; 60 | if (args.length > 0) { 61 | port = Integer.parseInt(args[0]); 62 | } else { 63 | port = 8082; 64 | } 65 | new MyServer(port).run(); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/MyServerHandler.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 ServerHandler. 9 | * 10 | * @since 1.0.0 2019年12月16日 11 | * @author Way Lau 12 | */ 13 | public class MyServerHandler extends SimpleChannelInboundHandler { 14 | 15 | @Override 16 | protected void channelRead0(ChannelHandlerContext ctx, Object obj) throws Exception { 17 | Channel incoming = ctx.channel(); 18 | 19 | if (obj instanceof Msg) { 20 | Msg msg = (Msg) obj; 21 | System.out.println("Client->Server:" + incoming.remoteAddress() + msg.getBody()); 22 | incoming.write(obj); 23 | } 24 | } 25 | 26 | @Override 27 | public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { 28 | ctx.flush(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/jackcon/JacksonBean.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.codec.jackcon; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | /** 7 | * POJO: Jackson Bean. 8 | * 9 | * @since 1.0.0 2020年1月2日 10 | * @author Way Lau 11 | */ 12 | public class JacksonBean { 13 | 14 | private int age; 15 | private String name; 16 | private List sons; 17 | private Map addrs; 18 | 19 | public int getAge() { 20 | return age; 21 | } 22 | 23 | public void setAge(int age) { 24 | this.age = age; 25 | } 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | 31 | public void setName(String name) { 32 | this.name = name; 33 | } 34 | 35 | public List getSons() { 36 | return sons; 37 | } 38 | 39 | public void setSons(List sons) { 40 | this.sons = sons; 41 | } 42 | 43 | public Map getAddrs() { 44 | return addrs; 45 | } 46 | 47 | public void setAddrs(Map addrs) { 48 | this.addrs = addrs; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/jackcon/JacksonClient.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.codec.jackcon; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import io.netty.bootstrap.Bootstrap; 9 | import io.netty.channel.Channel; 10 | import io.netty.channel.EventLoopGroup; 11 | import io.netty.channel.nio.NioEventLoopGroup; 12 | import io.netty.channel.socket.nio.NioSocketChannel; 13 | 14 | 15 | /** 16 | * Jackson Client. 17 | * 18 | * @since 1.0.0 2020年1月2日 19 | * @author Way Lau 20 | */ 21 | public class JacksonClient { 22 | 23 | public static void main(String[] args) throws Exception{ 24 | new JacksonClient("localhost", 8082).run(); 25 | } 26 | 27 | private final String host; 28 | private final int port; 29 | 30 | public JacksonClient(String host, int port){ 31 | this.host = host; 32 | this.port = port; 33 | } 34 | 35 | public void run() throws Exception{ 36 | EventLoopGroup group = new NioEventLoopGroup(); 37 | try { 38 | Bootstrap bootstrap = new Bootstrap() 39 | .group(group) 40 | .channel(NioSocketChannel.class) 41 | .handler(new JacksonClientInitializer()); 42 | 43 | Channel channel = bootstrap.connect(host, port).sync().channel(); 44 | 45 | // 发送对象 46 | JacksonBean user = new JacksonBean(); 47 | user.setAge(27); 48 | user.setName("waylau"); 49 | List sons = new ArrayList(); 50 | for (int i = 0;i <10; i++) { 51 | sons.add("Lucy"+i); 52 | sons.add("Lily"+i); 53 | } 54 | 55 | user.setSons(sons); 56 | Map addrs = new HashMap(); 57 | for (int i = 0;i <10; i++) { 58 | addrs.put("001"+i, "18998366112"); 59 | addrs.put("002"+i, "15014965012"); 60 | } 61 | 62 | user.setAddrs(addrs); 63 | channel.write(user); 64 | channel.flush(); 65 | 66 | // 等待连接关闭 67 | channel.closeFuture().sync(); 68 | } catch (Exception e) { 69 | e.printStackTrace(); 70 | } finally { 71 | group.shutdownGracefully(); 72 | } 73 | 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/jackcon/JacksonClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.codec.jackcon; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.SimpleChannelInboundHandler; 5 | 6 | /** 7 | * JacksonClient Handler. 8 | * 9 | * @since 1.0.0 2020年1月2日 10 | * @author Way Lau 11 | */ 12 | public class JacksonClientHandler extends 13 | SimpleChannelInboundHandler { 14 | 15 | @Override 16 | protected void channelRead0(ChannelHandlerContext ctx, Object obj) 17 | throws Exception { 18 | String jsonString = ""; 19 | if (obj instanceof JacksonBean) { 20 | JacksonBean user = (JacksonBean) obj; 21 | jsonString = JacksonMapper.getInstance().writeValueAsString(user); // 对象转为json字符串 22 | System.out.println("Server -> Client: " + jsonString); 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/jackcon/JacksonClientInitializer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.codec.jackcon; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelInitializer; 5 | import io.netty.channel.ChannelPipeline; 6 | 7 | /** 8 | * JacksonClient ChannelInitializer. 9 | * 10 | * @since 1.0.0 2020年1月2日 11 | * @author Way Lau 12 | */ 13 | public class JacksonClientInitializer extends 14 | ChannelInitializer { 15 | 16 | @Override 17 | protected void initChannel(Channel ch) throws Exception { 18 | ChannelPipeline pipeline = ch.pipeline(); 19 | pipeline.addLast(new JacksonDecoder(JacksonBean.class)); 20 | pipeline.addLast(new JacksonEncoder()); 21 | pipeline.addLast(new JacksonClientHandler()); 22 | } 23 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/jackcon/JacksonDecoder.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.codec.jackcon; 2 | 3 | import java.io.InputStream; 4 | import java.util.List; 5 | 6 | import com.fasterxml.jackson.databind.ObjectMapper; 7 | 8 | import io.netty.buffer.ByteBuf; 9 | import io.netty.buffer.ByteBufInputStream; 10 | import io.netty.channel.ChannelHandlerContext; 11 | import io.netty.handler.codec.ByteToMessageDecoder; 12 | 13 | /** 14 | * Jackson Decoder. 15 | * 16 | * @since 1.0.0 2020年1月2日 17 | * @author Way Lau 18 | */ 19 | public class JacksonDecoder extends ByteToMessageDecoder { 20 | 21 | private final Class clazz; 22 | 23 | public JacksonDecoder(Class clazz) { 24 | this.clazz = clazz; 25 | } 26 | 27 | @Override 28 | protected void decode(ChannelHandlerContext ctx, ByteBuf in, 29 | List out) throws Exception { 30 | InputStream byteBufInputStream = new ByteBufInputStream(in); 31 | ObjectMapper mapper = JacksonMapper.getInstance(); 32 | out.add(mapper.readValue(byteBufInputStream, clazz)); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/jackcon/JacksonEncoder.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.codec.jackcon; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | 5 | import io.netty.buffer.ByteBuf; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.handler.codec.MessageToByteEncoder; 8 | 9 | /** 10 | * Jackson Encoder. 11 | * 12 | * @since 1.0.0 2020年1月2日 13 | * @author Way Lau 14 | */ 15 | public class JacksonEncoder extends MessageToByteEncoder { 16 | 17 | @Override 18 | protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) 19 | throws Exception { 20 | 21 | ObjectMapper mapper = JacksonMapper.getInstance(); 22 | byte[] body = mapper.writeValueAsBytes(msg); // 将对象转换为byte 23 | out.writeBytes(body); // 消息体中包含我们要发送的数据 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/jackcon/JacksonMapper.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.codec.jackcon; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | 5 | /** 6 | * ObjectMapper instance. 7 | * 8 | * @since 1.0.0 2020年1月2日 9 | * @author Way Lau 10 | */ 11 | public class JacksonMapper { 12 | 13 | private static final ObjectMapper MAPPER = new ObjectMapper(); 14 | 15 | public static ObjectMapper getInstance() { 16 | return MAPPER; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/jackcon/JacksonServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.codec.jackcon; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelOption; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.nio.NioEventLoopGroup; 8 | import io.netty.channel.socket.nio.NioServerSocketChannel; 9 | import io.netty.handler.logging.LogLevel; 10 | import io.netty.handler.logging.LoggingHandler; 11 | 12 | 13 | /** 14 | * Jackson Server. 15 | * 16 | * @since 1.0.0 2020年1月2日 17 | * @author Way Lau 18 | */ 19 | public final class JacksonServer { 20 | 21 | static final int PORT = 8082; 22 | 23 | public static void main(String[] args) throws Exception { 24 | 25 | // Configure the server. 26 | EventLoopGroup bossGroup = new NioEventLoopGroup(1); 27 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 28 | try { 29 | ServerBootstrap b = new ServerBootstrap(); 30 | b.group(bossGroup, workerGroup) 31 | .channel(NioServerSocketChannel.class) 32 | .option(ChannelOption.SO_BACKLOG, 100) 33 | .childOption(ChannelOption.SO_KEEPALIVE, true) 34 | .handler(new LoggingHandler(LogLevel.INFO)) 35 | .childHandler(new JacksonServerInitializer()); 36 | 37 | // Start the server. 38 | ChannelFuture f = b.bind(PORT).sync(); 39 | 40 | // Wait until the server socket is closed. 41 | f.channel().closeFuture().sync(); 42 | } finally { 43 | // Shut down all event loops to terminate all threads. 44 | bossGroup.shutdownGracefully(); 45 | workerGroup.shutdownGracefully(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/jackcon/JacksonServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.codec.jackcon; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.SimpleChannelInboundHandler; 6 | 7 | /** 8 | * JacksonServer Handler 9 | * 10 | * @since 1.0.0 2020年1月2日 11 | * @author Way Lau 12 | */ 13 | public class JacksonServerHandler extends SimpleChannelInboundHandler { 14 | 15 | @Override 16 | protected void channelRead0(ChannelHandlerContext ctx, Object obj) throws Exception { 17 | String jsonString = ""; 18 | if (obj instanceof JacksonBean) { 19 | JacksonBean user = (JacksonBean) obj; 20 | ctx.writeAndFlush(user); 21 | jsonString = JacksonMapper.getInstance().writeValueAsString(user); // 对象转为json字符串 22 | System.out.println("Client -> Server: " + jsonString); 23 | } 24 | } 25 | 26 | @Override 27 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 28 | Channel incoming = ctx.channel(); 29 | System.out.println("SimpleChatClient:" + incoming.remoteAddress() + "异常"); 30 | // 当出现异常就关闭连接 31 | cause.printStackTrace(); 32 | ctx.close(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/jackcon/JacksonServerInitializer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.codec.jackcon; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelInitializer; 5 | import io.netty.channel.ChannelPipeline; 6 | 7 | /** 8 | * JacksonServer ChannelInitializer. 9 | * 10 | * @since 1.0.0 2020年1月2日 11 | * @author Way Lau 12 | */ 13 | public class JacksonServerInitializer extends ChannelInitializer { 14 | 15 | @Override 16 | protected void initChannel(Channel ch) throws Exception { 17 | ChannelPipeline pipeline = ch.pipeline(); 18 | pipeline.addLast(new JacksonDecoder(JacksonBean.class)); 19 | pipeline.addLast(new JacksonEncoder()); 20 | pipeline.addLast(new JacksonServerHandler()); 21 | } 22 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/jackcon/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * 说明:使用 Jackson json 来执行序列化 6 | * @author waylau.com 2015年11月8日 7 | */ 8 | package com.waylau.netty.demo.codec.jackcon; -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/serialization/SerializationBean.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.codec.serialization; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * POJO: a Serialization Bean 7 | * 8 | * @since 1.0.0 2020年1月2日 9 | * @author Way Lau 10 | */ 11 | public class SerializationBean implements Serializable { 12 | 13 | private static final long serialVersionUID = 3235432002462705915L; 14 | private int age; 15 | private String name; 16 | 17 | public int getAge() { 18 | return age; 19 | } 20 | 21 | public void setAge(int age) { 22 | this.age = age; 23 | } 24 | 25 | public String getName() { 26 | return name; 27 | } 28 | 29 | public void setName(String name) { 30 | this.name = name; 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return "SerializationBean [age=" + age + ", name=" + name + "]"; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/serialization/SerializationClient.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.codec.serialization; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.Channel; 5 | import io.netty.channel.EventLoopGroup; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import io.netty.channel.socket.nio.NioSocketChannel; 8 | 9 | 10 | /** 11 | * Serialization Client. 12 | * 13 | * @since 1.0.0 2020年1月2日 14 | * @author Way Lau 15 | */ 16 | public class SerializationClient { 17 | 18 | public static void main(String[] args) throws Exception{ 19 | new SerializationClient("localhost", 8082).run(); 20 | } 21 | 22 | private final String host; 23 | private final int port; 24 | 25 | public SerializationClient(String host, int port){ 26 | this.host = host; 27 | this.port = port; 28 | } 29 | 30 | public void run() throws Exception{ 31 | EventLoopGroup group = new NioEventLoopGroup(); 32 | try { 33 | Bootstrap bootstrap = new Bootstrap() 34 | .group(group) 35 | .channel(NioSocketChannel.class) 36 | .handler(new SerializationClientInitializer()); 37 | 38 | Channel channel = bootstrap.connect(host, port).sync().channel(); 39 | 40 | SerializationBean user = new SerializationBean(); 41 | 42 | for (int i = 0; i < 10; i++) { 43 | user = new SerializationBean(); 44 | user.setAge(i); 45 | user.setName("waylau"); 46 | channel.write(user); 47 | } 48 | channel.flush(); 49 | 50 | // 等待连接关闭 51 | channel.closeFuture().sync(); 52 | } catch (Exception e) { 53 | e.printStackTrace(); 54 | } finally { 55 | group.shutdownGracefully(); 56 | } 57 | 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/serialization/SerializationClientHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.netty.demo.codec.serialization; 5 | 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.SimpleChannelInboundHandler; 8 | 9 | /** 10 | * SerializationClient Handler. 11 | * 12 | * @since 1.0.0 2020年1月2日 13 | * @author Way Lau 14 | */ 15 | public class SerializationClientHandler extends 16 | SimpleChannelInboundHandler { 17 | 18 | @Override 19 | protected void channelRead0(ChannelHandlerContext ctx, Object obj) 20 | throws Exception { 21 | if (obj instanceof SerializationBean) { 22 | SerializationBean user = (SerializationBean) obj; 23 | System.out.println("Server -> Client: " + user); 24 | } 25 | 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/serialization/SerializationClientInitializer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.codec.serialization; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelInitializer; 5 | import io.netty.channel.ChannelPipeline; 6 | import io.netty.handler.codec.serialization.ClassResolvers; 7 | import io.netty.handler.codec.serialization.ObjectDecoder; 8 | import io.netty.handler.codec.serialization.ObjectEncoder; 9 | 10 | /** 11 | * SerializationClient Initializer. 12 | * 13 | * @since 1.0.0 2020年1月2日 14 | * @author Way Lau 15 | */ 16 | public class SerializationClientInitializer extends 17 | ChannelInitializer { 18 | 19 | private final static int MAX_OBJECT_SIZE = 1024 * 1024; 20 | 21 | @Override 22 | protected void initChannel(Channel ch) throws Exception { 23 | ChannelPipeline pipeline = ch.pipeline(); 24 | pipeline.addLast(new ObjectDecoder(MAX_OBJECT_SIZE, 25 | ClassResolvers.weakCachingConcurrentResolver(this.getClass() 26 | .getClassLoader()))); 27 | pipeline.addLast(new ObjectEncoder()); 28 | pipeline.addLast(new SerializationClientHandler()); 29 | } 30 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/serialization/SerializationServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.codec.serialization; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelOption; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.nio.NioEventLoopGroup; 8 | import io.netty.channel.socket.nio.NioServerSocketChannel; 9 | import io.netty.handler.logging.LogLevel; 10 | import io.netty.handler.logging.LoggingHandler; 11 | 12 | 13 | /** 14 | * Serialization Server. 15 | * 16 | * @since 1.0.0 2020年1月2日 17 | * @author Way Lau 18 | */ 19 | public final class SerializationServer { 20 | 21 | static final int PORT = 8082; 22 | 23 | public static void main(String[] args) throws Exception { 24 | 25 | // Configure the server. 26 | EventLoopGroup bossGroup = new NioEventLoopGroup(1); 27 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 28 | try { 29 | ServerBootstrap b = new ServerBootstrap(); 30 | b.group(bossGroup, workerGroup) 31 | .channel(NioServerSocketChannel.class) 32 | .option(ChannelOption.SO_BACKLOG, 100) 33 | .childOption(ChannelOption.SO_KEEPALIVE, true) 34 | .handler(new LoggingHandler(LogLevel.INFO)) 35 | .childHandler(new SerializationServerInitializer()); 36 | 37 | // Start the server. 38 | ChannelFuture f = b.bind(PORT).sync(); 39 | 40 | // Wait until the server socket is closed. 41 | f.channel().closeFuture().sync(); 42 | } finally { 43 | // Shut down all event loops to terminate all threads. 44 | bossGroup.shutdownGracefully(); 45 | workerGroup.shutdownGracefully(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/serialization/SerializationServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.codec.serialization; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.SimpleChannelInboundHandler; 5 | 6 | /** 7 | * SerializationServer Handler. 8 | * 9 | * @since 1.0.0 2020年1月2日 10 | * @author Way Lau 11 | */ 12 | public class SerializationServerHandler extends SimpleChannelInboundHandler { 13 | 14 | @Override 15 | protected void channelRead0(ChannelHandlerContext ctx, Object obj) throws Exception { 16 | if (obj instanceof SerializationBean) { 17 | SerializationBean user = (SerializationBean) obj; 18 | ctx.writeAndFlush(user); 19 | System.out.println("Client -> Server: " + user); 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/serialization/SerializationServerInitializer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.codec.serialization; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelInitializer; 5 | import io.netty.channel.ChannelPipeline; 6 | import io.netty.handler.codec.serialization.ClassResolvers; 7 | import io.netty.handler.codec.serialization.ObjectDecoder; 8 | import io.netty.handler.codec.serialization.ObjectEncoder; 9 | 10 | /** 11 | * SerializationServer ChannelInitializer. 12 | * 13 | * @since 1.0.0 2020年1月2日 14 | * @author Way Lau 15 | */ 16 | public class SerializationServerInitializer extends ChannelInitializer { 17 | 18 | private final static int MAX_OBJECT_SIZE = 1024 * 1024; 19 | 20 | @Override 21 | protected void initChannel(Channel ch) throws Exception { 22 | ChannelPipeline pipeline = ch.pipeline(); 23 | pipeline.addLast(new ObjectDecoder(MAX_OBJECT_SIZE, 24 | ClassResolvers.weakCachingConcurrentResolver(this.getClass() 25 | .getClassLoader()))); 26 | pipeline.addLast(new ObjectEncoder()); 27 | pipeline.addLast(new SerializationServerHandler()); 28 | } 29 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/serialization/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * 说明:使用 Netty 自带的序列化工具对 Java 对象进行序列化 6 | * 7 | * @author waylau.com 2015年11月7日 8 | */ 9 | package com.waylau.netty.demo.codec.serialization; -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/codec/消息格式.md: -------------------------------------------------------------------------------- 1 | ## 消息格式 2 | 3 | 类型 | 名称 | 字节序列 | 取值范围 | 备注 4 | --- | ----- | ---------| --------- |---- 5 | 消息头 | msgType | 0 |0x00-0xff |消息类型 6 | 消息头 | len |1-4 |0-2147483647 |消息体长度 7 | 消息体 | body |变长 |0- |消息体 8 | 9 | 10 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/decoder/MyLineBasedFrameDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to https://waylau.com 3 | */ 4 | package com.waylau.netty.demo.decoder; 5 | 6 | import io.netty.handler.codec.LineBasedFrameDecoder; 7 | 8 | /** 9 | * My LineBasedFrameDecoder. 10 | * 11 | * @since 1.0.0 2019年12月12日 12 | * @author Way Lau 13 | */ 14 | public class MyLineBasedFrameDecoder extends LineBasedFrameDecoder { 15 | 16 | private final static int MAX_LENGTH = 1024; // 帧的最大长度 17 | 18 | public MyLineBasedFrameDecoder() { 19 | super(MAX_LENGTH); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/decoder/MyLineBasedFrameDecoderChannelInitializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to https://waylau.com 3 | */ 4 | package com.waylau.netty.demo.decoder; 5 | 6 | import io.netty.channel.ChannelInitializer; 7 | import io.netty.channel.socket.SocketChannel; 8 | import io.netty.handler.codec.string.StringDecoder; 9 | 10 | /** 11 | * My LineBasedFrameDecoder ChannelInitializer。 12 | * 13 | * @since 1.0.0 2019年12月12日 14 | * @author Way Lau 15 | */ 16 | public class MyLineBasedFrameDecoderChannelInitializer extends ChannelInitializer { 17 | 18 | @Override 19 | protected void initChannel(SocketChannel channel) { 20 | // 基于换行符号 21 | channel.pipeline().addLast(new MyLineBasedFrameDecoder()); 22 | 23 | // 解码转String 24 | channel.pipeline().addLast(new StringDecoder()); 25 | 26 | // 自定义ChannelHandler 27 | channel.pipeline().addLast(new MyLineBasedFrameDecoderServerHandler()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/decoder/MyLineBasedFrameDecoderServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to https://waylau.com 3 | */ 4 | package com.waylau.netty.demo.decoder; 5 | 6 | import io.netty.bootstrap.ServerBootstrap; 7 | import io.netty.channel.ChannelFuture; 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.nio.NioServerSocketChannel; 12 | 13 | /** 14 | * My LineBasedFrameDecoder Server。 15 | * 16 | * @since 1.0.0 2019年12月12日 17 | * @author Way Lau 18 | */ 19 | public class MyLineBasedFrameDecoderServer { 20 | 21 | public static int DEFAULT_PORT = 8023; 22 | 23 | public static void main(String[] args) throws Exception { 24 | int port = DEFAULT_PORT; 25 | 26 | // 多线程事件循环器 27 | EventLoopGroup bossGroup = new NioEventLoopGroup(1); // boss 28 | EventLoopGroup workerGroup = new NioEventLoopGroup(); // worker 29 | 30 | try { 31 | // 启动NIO服务的引导程序类 32 | ServerBootstrap b = new ServerBootstrap(); 33 | 34 | b.group(bossGroup, workerGroup) // 设置EventLoopGroup 35 | .channel(NioServerSocketChannel.class) // 指明新的Channel的类型 36 | .childHandler(new MyLineBasedFrameDecoderChannelInitializer()) // 指定ChannelHandler 37 | .option(ChannelOption.SO_BACKLOG, 128) // 设置的ServerChannel的一些选项 38 | .childOption(ChannelOption.SO_KEEPALIVE, true); // 设置的ServerChannel的子Channel的选项 39 | 40 | // 绑定端口,开始接收进来的连接 41 | ChannelFuture f = b.bind(port).sync(); 42 | 43 | System.out.println("MyLineBasedFrameDecoderServer已启动,端口:" + port); 44 | 45 | // 等待服务器 socket 关闭 。 46 | // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。 47 | f.channel().closeFuture().sync(); 48 | } finally { 49 | 50 | // 优雅的关闭 51 | workerGroup.shutdownGracefully(); 52 | bossGroup.shutdownGracefully(); 53 | } 54 | 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/decoder/MyLineBasedFrameDecoderServerHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to https://waylau.com 3 | */ 4 | package com.waylau.netty.demo.decoder; 5 | 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.ChannelInboundHandlerAdapter; 8 | 9 | /** 10 | * My LineBasedFrameDecoder ServerHandler。 11 | * 12 | * @since 1.0.0 2019年12月12日 13 | * @author Way Lau 14 | */ 15 | public class MyLineBasedFrameDecoderServerHandler extends ChannelInboundHandlerAdapter { 16 | 17 | @Override 18 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 19 | // 接收msg消息,此处已经无需解码了 20 | System.out.println("Client -> Server: " + msg); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/discard/DiscardServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.discard; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | 5 | import io.netty.channel.ChannelFuture; 6 | import io.netty.channel.ChannelInitializer; 7 | import io.netty.channel.ChannelOption; 8 | import io.netty.channel.EventLoopGroup; 9 | import io.netty.channel.nio.NioEventLoopGroup; 10 | import io.netty.channel.socket.SocketChannel; 11 | import io.netty.channel.socket.nio.NioServerSocketChannel; 12 | 13 | /** 14 | * Discard Server. 15 | * 丢弃任何进入的数据. 16 | * 17 | * @since 1.0.0 2019年10月5日 18 | * @author Way Lau 19 | */ 20 | public class DiscardServer { 21 | 22 | private int port; 23 | 24 | public DiscardServer(int port) { 25 | this.port = port; 26 | } 27 | 28 | public void run() throws Exception { 29 | EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1) 30 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 31 | try { 32 | ServerBootstrap b = new ServerBootstrap(); // (2) 33 | b.group(bossGroup, workerGroup) 34 | .channel(NioServerSocketChannel.class) // (3) 35 | .childHandler(new ChannelInitializer() { // (4) 36 | @Override 37 | public void initChannel(SocketChannel ch) throws Exception { 38 | 39 | // 添加ChannelHandler到ChannelPipeline 40 | ch.pipeline().addLast(new DiscardServerHandler()); 41 | } 42 | }) 43 | .option(ChannelOption.SO_BACKLOG, 128) // (5) 44 | .childOption(ChannelOption.SO_KEEPALIVE, true); // (6) 45 | 46 | // 绑定端口,开始接收进来的连接 47 | ChannelFuture f = b.bind(port).sync(); // (7) 48 | 49 | System.out.println("DiscardServer已启动,端口:" + port); 50 | 51 | // 等待服务器 socket 关闭 。 52 | // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。 53 | f.channel().closeFuture().sync(); 54 | } finally { 55 | workerGroup.shutdownGracefully(); 56 | bossGroup.shutdownGracefully(); 57 | } 58 | } 59 | 60 | public static void main(String[] args) throws Exception { 61 | int port; 62 | if (args.length > 0) { 63 | port = Integer.parseInt(args[0]); 64 | } else { 65 | port = 8080; 66 | } 67 | new DiscardServer(port).run(); 68 | } 69 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/discard/DiscardServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.discard; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelInboundHandlerAdapter; 6 | import io.netty.util.ReferenceCountUtil; 7 | 8 | /** 9 | * Discard Server Handler. 10 | * 11 | * @since 1.0.0 2019年10月5日 12 | * @author Way Lau 13 | */ 14 | public class DiscardServerHandler extends ChannelInboundHandlerAdapter { // (1) 15 | 16 | @Override 17 | public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2) 18 | /* 19 | // 默默地丢弃收到的数据 20 | ((ByteBuf) msg).release(); // (3) 21 | */ 22 | 23 | /* 24 | try { 25 | // Do something with msg 26 | } finally { 27 | ReferenceCountUtil.release(msg); 28 | } 29 | */ 30 | 31 | ByteBuf in = (ByteBuf) msg; 32 | try { 33 | while (in.isReadable()) { // (1) 34 | 35 | // 打印消息内容 36 | System.out.print((char) in.readByte()); 37 | System.out.flush(); 38 | } 39 | } finally { 40 | 41 | // 释放消息 42 | ReferenceCountUtil.release(msg); // (2) 43 | } 44 | 45 | } 46 | 47 | @Override 48 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4) 49 | // 当出现异常就关闭连接 50 | cause.printStackTrace(); 51 | ctx.close(); 52 | } 53 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/echo/DatagramChannelEchoClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.echo; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelInboundHandlerAdapter; 5 | import io.netty.channel.socket.DatagramPacket; 6 | import io.netty.util.CharsetUtil; 7 | 8 | /** 9 | * DatagramChannel Echo Client Handler. 10 | * 11 | * @since 1.0.0 2019年10月24日 12 | * @author Way Lau 13 | */ 14 | public class DatagramChannelEchoClientHandler extends ChannelInboundHandlerAdapter { 15 | @Override 16 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 17 | 18 | // 从管道读消息 19 | DatagramPacket packet = (DatagramPacket) msg; // 转为DatagramPacket类型 20 | String m = packet.content().toString(CharsetUtil.UTF_8); // 转为字符串 21 | System.out.println( "echo :" + m); 22 | } 23 | 24 | @Override 25 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 26 | 27 | // 当出现异常就关闭连接 28 | cause.printStackTrace(); 29 | ctx.close(); 30 | } 31 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/echo/DatagramChannelEchoServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to https://waylau.com 3 | */ 4 | package com.waylau.netty.demo.echo; 5 | 6 | import io.netty.bootstrap.Bootstrap; 7 | import io.netty.channel.ChannelFuture; 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.nio.NioDatagramChannel; 12 | 13 | /** 14 | * DatagramChannel Echo Server. 15 | * 16 | * @since 1.0.0 2019年10月22日 17 | * @author Way Lau 18 | */ 19 | public class DatagramChannelEchoServer { 20 | 21 | public static int DEFAULT_PORT = 7; 22 | 23 | public static void main(String[] args) throws Exception { 24 | int port; 25 | 26 | try { 27 | port = Integer.parseInt(args[0]); 28 | } catch (RuntimeException ex) { 29 | port = DEFAULT_PORT; 30 | } 31 | 32 | // 配置事件循环器 33 | EventLoopGroup group = new NioEventLoopGroup(); 34 | 35 | try { 36 | // 启动NIO服务的引导程序类 37 | Bootstrap b = new Bootstrap(); 38 | 39 | b.group(group) // 设置EventLoopGroup 40 | .channel(NioDatagramChannel.class) // 指明新的Channel的类型 41 | .option(ChannelOption.SO_BROADCAST, true) // 设置的Channel的一些选项 42 | .handler(new DatagramChannelEchoServerHandler()); // 指定ChannelHandler 43 | 44 | // 绑定端口 45 | ChannelFuture f = b.bind(port).sync(); 46 | 47 | System.out.println("DatagramChannelEchoServer已启动,端口:" + port); 48 | 49 | // 等待服务器 socket 关闭 。 50 | // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。 51 | f.channel().closeFuture().sync(); 52 | } finally { 53 | 54 | // 优雅的关闭 55 | group.shutdownGracefully(); 56 | } 57 | 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/echo/DatagramChannelEchoServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.echo; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelInboundHandlerAdapter; 5 | import io.netty.channel.socket.DatagramPacket; 6 | 7 | /** 8 | * DatagramChannel Echo Server Handler. 9 | * 10 | * @since 1.0.0 2019年10月24日 11 | * @author Way Lau 12 | */ 13 | public class DatagramChannelEchoServerHandler extends ChannelInboundHandlerAdapter { 14 | 15 | @Override 16 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 17 | // 消息转为DatagramPacket类型 18 | DatagramPacket packet = (DatagramPacket)msg; 19 | 20 | System.out.println(packet.sender() + " -> Server :" + msg); 21 | 22 | // 构建新DatagramPacket 23 | DatagramPacket data = new DatagramPacket(packet.content(), packet.sender()); 24 | 25 | // 写消息到管道 26 | ctx.write(data);// 写消息 27 | ctx.flush(); // 刷新消息 28 | 29 | // 上面两个方法等同于 ctx.writeAndFlush(data); 30 | } 31 | 32 | @Override 33 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 34 | 35 | // 当出现异常就关闭连接 36 | cause.printStackTrace(); 37 | ctx.close(); 38 | } 39 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/echo/EchoClient.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.echo; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | import java.net.UnknownHostException; 7 | import java.nio.ByteBuffer; 8 | 9 | import io.netty.bootstrap.Bootstrap; 10 | import io.netty.buffer.ByteBuf; 11 | import io.netty.buffer.Unpooled; 12 | import io.netty.channel.Channel; 13 | import io.netty.channel.ChannelFuture; 14 | import io.netty.channel.ChannelOption; 15 | import io.netty.channel.EventLoopGroup; 16 | import io.netty.channel.nio.NioEventLoopGroup; 17 | import io.netty.channel.socket.nio.NioSocketChannel; 18 | 19 | /** 20 | * Echo Client. 21 | * 22 | * @since 1.0.0 2019年10月2日 23 | * @author Way Lau 24 | */ 25 | public final class EchoClient { 26 | 27 | public static void main(String[] args) throws Exception { 28 | if (args.length != 2) { 29 | System.err.println("用法: java EchoClient "); 30 | System.exit(1); 31 | } 32 | 33 | String hostName = args[0]; 34 | int portNumber = Integer.parseInt(args[1]); 35 | 36 | // 配置客户端 37 | EventLoopGroup group = new NioEventLoopGroup(); 38 | try { 39 | Bootstrap b = new Bootstrap(); 40 | b.group(group) 41 | .channel(NioSocketChannel.class) 42 | .option(ChannelOption.TCP_NODELAY, true) 43 | .handler(new EchoClientHandler()); 44 | 45 | // 连接到服务器 46 | ChannelFuture f = b.connect(hostName, portNumber).sync(); 47 | 48 | Channel channel = f.channel(); 49 | ByteBuffer writeBuffer = ByteBuffer.allocate(32); 50 | try (BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in))) { 51 | String userInput; 52 | while ((userInput = stdIn.readLine()) != null) { 53 | writeBuffer.put(userInput.getBytes()); 54 | writeBuffer.flip(); 55 | writeBuffer.rewind(); 56 | 57 | // 转为ByteBuf 58 | ByteBuf buf = Unpooled.copiedBuffer(writeBuffer); 59 | 60 | // 写消息到管道 61 | channel.writeAndFlush(buf); 62 | 63 | // 清理缓冲区 64 | writeBuffer.clear(); 65 | } 66 | } catch (UnknownHostException e) { 67 | System.err.println("不明主机,主机名为: " + hostName); 68 | System.exit(1); 69 | } catch (IOException e) { 70 | System.err.println("不能从主机中获取I/O,主机名为:" + hostName); 71 | System.exit(1); 72 | } 73 | } finally { 74 | 75 | // 优雅的关闭 76 | group.shutdownGracefully(); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/echo/EchoClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.echo; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelInboundHandlerAdapter; 6 | import io.netty.util.CharsetUtil; 7 | 8 | /** 9 | * Echo Client Handler. 10 | * 11 | * @since 1.0.0 2019年10月2日 12 | * @author Way Lau 13 | */ 14 | public class EchoClientHandler extends ChannelInboundHandlerAdapter { 15 | @Override 16 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 17 | 18 | // 从管道读消息 19 | ByteBuf buf = (ByteBuf) msg; // 转为ByteBuf类型 20 | String m = buf.toString(CharsetUtil.UTF_8); // 转为字符串 21 | System.out.println( "echo :" + m); 22 | } 23 | 24 | @Override 25 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 26 | 27 | // 当出现异常就关闭连接 28 | cause.printStackTrace(); 29 | ctx.close(); 30 | } 31 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/echo/EchoServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.echo; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelOption; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.nio.NioEventLoopGroup; 8 | import io.netty.channel.socket.nio.NioServerSocketChannel; 9 | 10 | /** 11 | * Echo Server. 12 | * 13 | * @since 1.0.0 2019年10月2日 14 | * @author Way Lau 15 | */ 16 | public class EchoServer { 17 | 18 | public static int DEFAULT_PORT = 7; 19 | 20 | public static void main(String[] args) throws Exception { 21 | int port; 22 | 23 | try { 24 | port = Integer.parseInt(args[0]); 25 | } catch (RuntimeException ex) { 26 | port = DEFAULT_PORT; 27 | } 28 | 29 | // 多线程事件循环器 30 | EventLoopGroup bossGroup = new NioEventLoopGroup(); // boss 31 | EventLoopGroup workerGroup = new NioEventLoopGroup(); // worker 32 | 33 | try { 34 | // 启动NIO服务的引导程序类 35 | ServerBootstrap b = new ServerBootstrap(); 36 | 37 | b.group(bossGroup, workerGroup) // 设置EventLoopGroup 38 | .channel(NioServerSocketChannel.class) // 指明新的Channel的类型 39 | .childHandler(new EchoServerHandler()) // 指定ChannelHandler 40 | .option(ChannelOption.SO_BACKLOG, 128) // 设置的ServerChannel的一些选项 41 | .childOption(ChannelOption.SO_KEEPALIVE, true); // 设置的ServerChannel的子Channel的选项 42 | 43 | // 绑定端口,开始接收进来的连接 44 | ChannelFuture f = b.bind(port).sync(); 45 | 46 | System.out.println("EchoServer已启动,端口:" + port); 47 | 48 | // 等待服务器 socket 关闭 。 49 | // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。 50 | f.channel().closeFuture().sync(); 51 | } finally { 52 | 53 | // 优雅的关闭 54 | workerGroup.shutdownGracefully(); 55 | bossGroup.shutdownGracefully(); 56 | } 57 | 58 | } 59 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/echo/EchoServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.echo; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelInboundHandlerAdapter; 5 | 6 | /** 7 | * Echo Server Handler. 8 | * 9 | * @since 1.0.0 2019年10月2日 10 | * @author Way Lau 11 | */ 12 | public class EchoServerHandler extends ChannelInboundHandlerAdapter { 13 | 14 | @Override 15 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 16 | System.out.println(ctx.channel().remoteAddress() + " -> Server :" + msg); 17 | 18 | // 写消息到管道 19 | ctx.write(msg);// 写消息 20 | ctx.flush(); // 冲刷消息 21 | 22 | // 上面两个方法等同于 ctx.writeAndFlush(msg); 23 | } 24 | 25 | @Override 26 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 27 | 28 | // 当出现异常就关闭连接 29 | cause.printStackTrace(); 30 | ctx.close(); 31 | } 32 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/echo/EpollEchoServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.echo; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelOption; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.epoll.EpollEventLoopGroup; 8 | import io.netty.channel.epoll.EpollServerSocketChannel; 9 | 10 | /** 11 | * epoll Echo Server. 12 | * Only supported on Linux. 13 | * 14 | * @since 1.0.0 2020年1月4日 15 | * @author Way Lau 16 | */ 17 | public class EpollEchoServer { 18 | 19 | public static int DEFAULT_PORT = 7; 20 | 21 | public static void main(String[] args) throws Exception { 22 | int port; 23 | 24 | try { 25 | port = Integer.parseInt(args[0]); 26 | } catch (RuntimeException ex) { 27 | port = DEFAULT_PORT; 28 | } 29 | 30 | // 多线程事件循环器 31 | EventLoopGroup bossGroup = new EpollEventLoopGroup(); // boss 32 | EventLoopGroup workerGroup = new EpollEventLoopGroup(); // worker 33 | 34 | try { 35 | // 启动NIO服务的引导程序类 36 | ServerBootstrap b = new ServerBootstrap(); 37 | 38 | b.group(bossGroup, workerGroup) // 设置EventLoopGroup 39 | .channel(EpollServerSocketChannel.class) // 指明新的Channel的类型 40 | .childHandler(new EchoServerHandler()) // 指定ChannelHandler 41 | .option(ChannelOption.SO_BACKLOG, 128) // 设置的ServerChannel的一些选项 42 | .childOption(ChannelOption.SO_KEEPALIVE, true); // 设置的ServerChannel的子Channel的选项 43 | 44 | // 绑定端口,开始接收进来的连接 45 | ChannelFuture f = b.bind(port).sync(); 46 | 47 | System.out.println("EchoServer已启动,端口:" + port); 48 | 49 | // 等待服务器 socket 关闭 。 50 | // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。 51 | f.channel().closeFuture().sync(); 52 | } finally { 53 | 54 | // 优雅的关闭 55 | workerGroup.shutdownGracefully(); 56 | bossGroup.shutdownGracefully(); 57 | } 58 | 59 | } 60 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/echo/LocalEchoServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.echo; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelOption; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.local.LocalEventLoopGroup; 8 | import io.netty.channel.local.LocalServerChannel; 9 | 10 | /** 11 | * Local Echo Server. 12 | * 13 | * @since 1.0.0 2020年1月4日 14 | * @author Way Lau 15 | */ 16 | public class LocalEchoServer { 17 | 18 | public static int DEFAULT_PORT = 7; 19 | 20 | public static void main(String[] args) throws Exception { 21 | int port; 22 | 23 | try { 24 | port = Integer.parseInt(args[0]); 25 | } catch (RuntimeException ex) { 26 | port = DEFAULT_PORT; 27 | } 28 | 29 | // 多线程事件循环器 30 | EventLoopGroup bossGroup = new LocalEventLoopGroup(); // boss 31 | EventLoopGroup workerGroup = new LocalEventLoopGroup(); // worker 32 | 33 | try { 34 | // 启动NIO服务的引导程序类 35 | ServerBootstrap b = new ServerBootstrap(); 36 | 37 | b.group(bossGroup, workerGroup) // 设置EventLoopGroup 38 | .channel(LocalServerChannel.class) // 指明新的Channel的类型 39 | .childHandler(new EchoServerHandler()) // 指定ChannelHandler 40 | .option(ChannelOption.SO_BACKLOG, 128) // 设置的ServerChannel的一些选项 41 | .childOption(ChannelOption.SO_KEEPALIVE, true); // 设置的ServerChannel的子Channel的选项 42 | 43 | // 绑定端口,开始接收进来的连接 44 | ChannelFuture f = b.bind(port).sync(); 45 | 46 | System.out.println("EchoServer已启动,端口:" + port); 47 | 48 | // 等待服务器 socket 关闭 。 49 | // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。 50 | f.channel().closeFuture().sync(); 51 | } finally { 52 | 53 | // 优雅的关闭 54 | workerGroup.shutdownGracefully(); 55 | bossGroup.shutdownGracefully(); 56 | } 57 | 58 | } 59 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/echo/OioEchoServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.echo; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelOption; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.oio.OioEventLoopGroup; 8 | import io.netty.channel.socket.oio.OioServerSocketChannel; 9 | 10 | /** 11 | * OIO Echo Server. 12 | * 13 | * @since 1.0.0 2020年1月4日 14 | * @author Way Lau 15 | */ 16 | public class OioEchoServer { 17 | 18 | public static int DEFAULT_PORT = 7; 19 | 20 | public static void main(String[] args) throws Exception { 21 | int port; 22 | 23 | try { 24 | port = Integer.parseInt(args[0]); 25 | } catch (RuntimeException ex) { 26 | port = DEFAULT_PORT; 27 | } 28 | 29 | // 多线程事件循环器 30 | EventLoopGroup bossGroup = new OioEventLoopGroup(); // boss 31 | EventLoopGroup workerGroup = new OioEventLoopGroup(); // worker 32 | 33 | try { 34 | // 启动NIO服务的引导程序类 35 | ServerBootstrap b = new ServerBootstrap(); 36 | 37 | b.group(bossGroup, workerGroup) // 设置EventLoopGroup 38 | .channel(OioServerSocketChannel.class) // 指明新的Channel的类型 39 | .childHandler(new EchoServerHandler()) // 指定ChannelHandler 40 | .option(ChannelOption.SO_BACKLOG, 128) // 设置的ServerChannel的一些选项 41 | .childOption(ChannelOption.SO_KEEPALIVE, true); // 设置的ServerChannel的子Channel的选项 42 | 43 | // 绑定端口,开始接收进来的连接 44 | ChannelFuture f = b.bind(port).sync(); 45 | 46 | System.out.println("EchoServer已启动,端口:" + port); 47 | 48 | // 等待服务器 socket 关闭 。 49 | // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。 50 | f.channel().closeFuture().sync(); 51 | } finally { 52 | 53 | // 优雅的关闭 54 | workerGroup.shutdownGracefully(); 55 | bossGroup.shutdownGracefully(); 56 | } 57 | 58 | } 59 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/encoder/Msg.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.encoder; 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/encoder/MsgHeader.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.encoder; 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/encoder/MsgType.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.encoder; 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/encoder/MyClient.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.encoder; 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("decoder", new MyDecoder()); 43 | ch.pipeline().addLast("encoder", new MyEncoder()); 44 | ch.pipeline().addLast(new MyClientHandler()); 45 | 46 | } 47 | }); 48 | 49 | // 启动客户端 50 | ChannelFuture f = b.connect(host, port).sync(); 51 | 52 | while (true) { 53 | 54 | // 发送消息给服务器 55 | Msg msg = new Msg(); 56 | MsgHeader msgHeader = new MsgHeader(); 57 | msgHeader.setMsgType(MsgType.EMGW_LOGIN_REQ.getValue()); 58 | String body = "床前明月光,疑是地上霜。举头望明月,低头思故乡。"; 59 | 60 | byte[] bodyBytes = body.getBytes(Charset.forName("utf-8")); 61 | int bodySize = bodyBytes.length; 62 | msgHeader.setLen(bodySize); 63 | msg.setMsgHeader(msgHeader); 64 | msg.setBody(body); 65 | 66 | f.channel().writeAndFlush(msg); 67 | Thread.sleep(2000); 68 | } 69 | } finally { 70 | workerGroup.shutdownGracefully(); 71 | } 72 | } 73 | 74 | public static void main(String[] args) throws InterruptedException { 75 | new MyClient("localhost", 8082).run(); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/encoder/MyClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.encoder; 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 { 14 | 15 | @Override 16 | protected void channelRead0(ChannelHandlerContext ctx, Object obj) throws Exception { 17 | Channel incoming = ctx.channel(); 18 | 19 | if (obj instanceof Msg) { 20 | Msg msg = (Msg) obj; 21 | System.out.println("Server->Client:" + incoming.remoteAddress() + msg.getBody()); 22 | } else { 23 | System.out.println("Server->Client:" + incoming.remoteAddress() + obj.toString()); 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/encoder/MyDecoder.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.encoder; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.codec.LengthFieldBasedFrameDecoder; 6 | 7 | /** 8 | * My Decoder. 9 | * 10 | * @since 1.0.0 2019年12月16日 11 | * @author Way Lau 12 | */ 13 | public class MyDecoder extends LengthFieldBasedFrameDecoder { 14 | 15 | private static final int MAX_FRAME_LENGTH = 1024 * 1024; 16 | private static final int LENGTH_FIELD_LENGTH = 4; 17 | private static final int LENGTH_FIELD_OFFSET = 1; 18 | private static final int LENGTH_ADJUSTMENT = 0; 19 | private static final int INITIAL_BYTES_TO_STRIP = 0; 20 | 21 | private static final int HEADER_SIZE = 5; 22 | private byte msgType; // 消息类型 23 | private int len; // 长度 24 | 25 | public MyDecoder() { 26 | super(MAX_FRAME_LENGTH, 27 | LENGTH_FIELD_OFFSET, LENGTH_FIELD_LENGTH, 28 | LENGTH_ADJUSTMENT, INITIAL_BYTES_TO_STRIP); 29 | } 30 | 31 | @Override 32 | protected Msg decode(ChannelHandlerContext ctx, ByteBuf in2) throws Exception { 33 | ByteBuf in = (ByteBuf) super.decode(ctx, in2); 34 | if (in == null) { 35 | return null; 36 | } 37 | 38 | // 校验头长度 39 | if (in.readableBytes() < HEADER_SIZE) { 40 | return null; 41 | } 42 | 43 | msgType = in.readByte(); 44 | len = in.readInt(); 45 | 46 | // 校验消息体长度 47 | if (in.readableBytes() < len) { 48 | return null; 49 | } 50 | 51 | ByteBuf buf = in.readBytes(len); 52 | byte[] req = new byte[buf.readableBytes()]; 53 | buf.readBytes(req); 54 | String body = new String(req, "UTF-8"); 55 | 56 | // ByteBuf转为Msg类型 57 | Msg msg = new Msg(); 58 | MsgHeader msgHeader = new MsgHeader(msgType, len); 59 | msg.setBody(body); 60 | msg.setMsgHeader(msgHeader); 61 | return msg; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/encoder/MyEncoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.netty.demo.encoder; 5 | 6 | import java.nio.charset.Charset; 7 | 8 | import io.netty.buffer.ByteBuf; 9 | import io.netty.channel.ChannelHandlerContext; 10 | import io.netty.handler.codec.MessageToByteEncoder; 11 | 12 | /** 13 | * My Encoder. 14 | * 15 | * @since 1.0.0 2019年12月16日 16 | * @author Way Lau 17 | */ 18 | public class MyEncoder extends MessageToByteEncoder { 19 | 20 | @Override 21 | protected void encode(ChannelHandlerContext ctx, Msg msg, ByteBuf out) throws Exception { 22 | if (msg == null | msg.getMsgHeader() == null) { 23 | throw new Exception("The encode message is null"); 24 | } 25 | 26 | // 获取消息头 27 | MsgHeader header = msg.getMsgHeader(); 28 | 29 | // 获取消息体 30 | String body = msg.getBody(); 31 | byte[] bodyBytes = body.getBytes(Charset.forName("utf-8")); 32 | 33 | // 计算消息体的长度 34 | int bodySize = bodyBytes.length; 35 | 36 | System.out.printf("MyEncoder header: %s, body: %s", header.getMsgType(), body); 37 | 38 | out.writeByte(MsgType.EMGW_LOGIN_RES.getValue()); 39 | out.writeInt(bodySize); 40 | out.writeBytes(bodyBytes); 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/encoder/MyServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.encoder; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelOption; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.channel.socket.nio.NioServerSocketChannel; 11 | 12 | /** 13 | * My Server. 14 | * 15 | * @since 1.0.0 2019年12月16日 16 | * @author Way Lau 17 | */ 18 | public class MyServer { 19 | 20 | private int port; 21 | 22 | public MyServer(int port) { 23 | this.port = port; 24 | } 25 | 26 | public void run() throws Exception { 27 | EventLoopGroup bossGroup = new NioEventLoopGroup(); 28 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 29 | try { 30 | ServerBootstrap b = new ServerBootstrap(); 31 | b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) 32 | .childHandler(new ChannelInitializer() { 33 | @Override 34 | public void initChannel(SocketChannel ch) throws Exception { 35 | ch.pipeline().addLast("decoder", new MyDecoder()); 36 | ch.pipeline().addLast("encoder", new MyEncoder()); 37 | ch.pipeline().addLast(new MyServerHandler()); 38 | } 39 | }).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true); 40 | 41 | ChannelFuture f = b.bind(port).sync(); 42 | 43 | System.out.println("Server start listen at " + port); 44 | 45 | f.channel().closeFuture().sync(); 46 | 47 | } finally { 48 | workerGroup.shutdownGracefully(); 49 | bossGroup.shutdownGracefully(); 50 | } 51 | } 52 | 53 | public static void main(String[] args) throws Exception { 54 | int port; 55 | if (args.length > 0) { 56 | port = Integer.parseInt(args[0]); 57 | } else { 58 | port = 8082; 59 | } 60 | new MyServer(port).run(); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/encoder/MyServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.encoder; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.SimpleChannelInboundHandler; 6 | 7 | /** 8 | * My ServerHandler. 9 | * 10 | * @since 1.0.0 2019年12月16日 11 | * @author Way Lau 12 | */ 13 | public class MyServerHandler extends SimpleChannelInboundHandler { 14 | 15 | @Override 16 | protected void channelRead0(ChannelHandlerContext ctx, Object obj) throws Exception { 17 | Channel incoming = ctx.channel(); 18 | 19 | if (obj instanceof Msg) { 20 | Msg msg = (Msg) obj; 21 | System.out.println("Client->Server:" + incoming.remoteAddress() + msg.getBody()); 22 | incoming.write(obj); 23 | } 24 | } 25 | 26 | @Override 27 | public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { 28 | ctx.flush(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/encoder/消息格式.md: -------------------------------------------------------------------------------- 1 | ## 消息格式 2 | 3 | 类型 | 名称 | 字节序列 | 取值范围 | 备注 4 | --- | ----- | ---------| --------- |---- 5 | 消息头 | msgType | 0 |0x00-0xff |消息类型 6 | 消息头 | len |1-4 |0-2147483647 |消息体长度 7 | 消息体 | body |变长 |0- |消息体 8 | 9 | 10 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/factorial/BigIntegerDecoder.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.factorial; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.codec.ByteToMessageDecoder; 6 | import io.netty.handler.codec.CorruptedFrameException; 7 | 8 | import java.math.BigInteger; 9 | import java.util.List; 10 | 11 | /** 12 | * Decodes the binary representation of a {@link BigInteger} prepended 13 | * with a magic number ('F' or 0x46) and a 32-bit integer length prefix into a 14 | * {@link BigInteger} instance. For example, { 'F', 0, 0, 0, 1, 42 } will be 15 | * decoded into new BigInteger("42"). 16 | */ 17 | public class BigIntegerDecoder extends ByteToMessageDecoder { 18 | 19 | @Override 20 | protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) { 21 | // Wait until the length prefix is available. 22 | if (in.readableBytes() < 5) { 23 | return; 24 | } 25 | 26 | in.markReaderIndex(); 27 | 28 | // Check the magic number. 29 | int magicNumber = in.readUnsignedByte(); 30 | if (magicNumber != 'F') { 31 | in.resetReaderIndex(); 32 | throw new CorruptedFrameException("Invalid magic number: " + magicNumber); 33 | } 34 | 35 | // Wait until the whole data is available. 36 | int dataLength = in.readInt(); 37 | if (in.readableBytes() < dataLength) { 38 | in.resetReaderIndex(); 39 | return; 40 | } 41 | 42 | // Convert the received data into a new BigInteger. 43 | byte[] decoded = new byte[dataLength]; 44 | in.readBytes(decoded); 45 | 46 | out.add(new BigInteger(decoded)); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/factorial/FactorialClient.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.factorial; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.EventLoopGroup; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import io.netty.channel.socket.nio.NioSocketChannel; 8 | import io.netty.handler.ssl.SslContext; 9 | import io.netty.handler.ssl.util.InsecureTrustManagerFactory; 10 | 11 | /** 12 | * Sends a sequence of integers to a {@link FactorialServer} to calculate 13 | * the factorial of the specified integer. 14 | */ 15 | public final class FactorialClient { 16 | 17 | static final boolean SSL = System.getProperty("ssl") != null; 18 | static final String HOST = System.getProperty("host", "127.0.0.1"); 19 | static final int PORT = Integer.parseInt(System.getProperty("port", "8322")); 20 | static final int COUNT = Integer.parseInt(System.getProperty("count", "1000")); 21 | 22 | public static void main(String[] args) throws Exception { 23 | // Configure SSL. 24 | final SslContext sslCtx; 25 | if (SSL) { 26 | sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE); 27 | } else { 28 | sslCtx = null; 29 | } 30 | 31 | EventLoopGroup group = new NioEventLoopGroup(); 32 | try { 33 | Bootstrap b = new Bootstrap(); 34 | b.group(group) 35 | .channel(NioSocketChannel.class) 36 | .handler(new FactorialClientInitializer(sslCtx)); 37 | 38 | // Make a new connection. 39 | ChannelFuture f = b.connect(HOST, PORT).sync(); 40 | 41 | // Get the handler instance to retrieve the answer. 42 | FactorialClientHandler handler = 43 | (FactorialClientHandler) f.channel().pipeline().last(); 44 | 45 | // Print out the answer. 46 | System.err.format("Factorial of %,d is: %,d", COUNT, handler.getFactorial()); 47 | } finally { 48 | group.shutdownGracefully(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/factorial/FactorialClientInitializer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.factorial; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.compression.ZlibCodecFactory; 7 | import io.netty.handler.codec.compression.ZlibWrapper; 8 | import io.netty.handler.ssl.SslContext; 9 | 10 | /** 11 | * Creates a newly configured {@link ChannelPipeline} for a client-side channel. 12 | */ 13 | public class FactorialClientInitializer extends ChannelInitializer { 14 | 15 | private final SslContext sslCtx; 16 | 17 | public FactorialClientInitializer(SslContext sslCtx) { 18 | this.sslCtx = sslCtx; 19 | } 20 | 21 | @Override 22 | public void initChannel(SocketChannel ch) { 23 | ChannelPipeline pipeline = ch.pipeline(); 24 | 25 | if (sslCtx != null) { 26 | pipeline.addLast(sslCtx.newHandler(ch.alloc(), FactorialClient.HOST, FactorialClient.PORT)); 27 | } 28 | 29 | // Enable stream compression (you can remove these two if unnecessary) 30 | pipeline.addLast(ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP)); 31 | pipeline.addLast(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP)); 32 | 33 | // Add the number codec first, 34 | pipeline.addLast(new BigIntegerDecoder()); 35 | pipeline.addLast(new NumberEncoder()); 36 | 37 | // and then business logic. 38 | pipeline.addLast(new FactorialClientHandler()); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/factorial/FactorialServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.factorial; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.EventLoopGroup; 5 | import io.netty.channel.nio.NioEventLoopGroup; 6 | import io.netty.channel.socket.nio.NioServerSocketChannel; 7 | import io.netty.handler.logging.LogLevel; 8 | import io.netty.handler.logging.LoggingHandler; 9 | import io.netty.handler.ssl.SslContext; 10 | import io.netty.handler.ssl.util.SelfSignedCertificate; 11 | 12 | /** 13 | * Receives a sequence of integers from a {@link FactorialClient} to calculate 14 | * the factorial of the specified integer. 15 | */ 16 | public final class FactorialServer { 17 | 18 | static final boolean SSL = System.getProperty("ssl") != null; 19 | static final int PORT = Integer.parseInt(System.getProperty("port", "8322")); 20 | 21 | public static void main(String[] args) throws Exception { 22 | // Configure SSL. 23 | final SslContext sslCtx; 24 | if (SSL) { 25 | SelfSignedCertificate ssc = new SelfSignedCertificate(); 26 | sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey()); 27 | } else { 28 | sslCtx = null; 29 | } 30 | 31 | EventLoopGroup bossGroup = new NioEventLoopGroup(1); 32 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 33 | try { 34 | ServerBootstrap b = new ServerBootstrap(); 35 | b.group(bossGroup, workerGroup) 36 | .channel(NioServerSocketChannel.class) 37 | .handler(new LoggingHandler(LogLevel.INFO)) 38 | .childHandler(new FactorialServerInitializer(sslCtx)); 39 | 40 | b.bind(PORT).sync().channel().closeFuture().sync(); 41 | } finally { 42 | bossGroup.shutdownGracefully(); 43 | workerGroup.shutdownGracefully(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/factorial/FactorialServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.factorial; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.SimpleChannelInboundHandler; 5 | 6 | import java.math.BigInteger; 7 | 8 | /** 9 | * Handler for a server-side channel. This handler maintains stateful 10 | * information which is specific to a certain channel using member variables. 11 | * Therefore, an instance of this handler can cover only one channel. You have 12 | * to create a new handler instance whenever you create a new channel and insert 13 | * this handler to avoid a race condition. 14 | */ 15 | public class FactorialServerHandler extends SimpleChannelInboundHandler { 16 | 17 | private BigInteger lastMultiplier = new BigInteger("1"); 18 | private BigInteger factorial = new BigInteger("1"); 19 | 20 | public void messageReceived(ChannelHandlerContext ctx, BigInteger msg) { 21 | // Calculate the cumulative factorial and send it to the client. 22 | lastMultiplier = msg; 23 | factorial = factorial.multiply(msg); 24 | ctx.writeAndFlush(factorial); 25 | } 26 | 27 | @Override 28 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 29 | System.err.printf("Factorial of %,d is: %,d%n", lastMultiplier, factorial); 30 | } 31 | 32 | @Override 33 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 34 | cause.printStackTrace(); 35 | ctx.close(); 36 | } 37 | 38 | @Override 39 | protected void channelRead0(ChannelHandlerContext arg0, BigInteger arg1) 40 | throws Exception { 41 | // TODO Auto-generated method stub 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/factorial/FactorialServerInitializer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.factorial; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.compression.ZlibCodecFactory; 7 | import io.netty.handler.codec.compression.ZlibWrapper; 8 | import io.netty.handler.ssl.SslContext; 9 | 10 | /** 11 | * Creates a newly configured {@link ChannelPipeline} for a server-side channel. 12 | */ 13 | public class FactorialServerInitializer extends ChannelInitializer { 14 | 15 | private final SslContext sslCtx; 16 | 17 | public FactorialServerInitializer(SslContext sslCtx) { 18 | this.sslCtx = sslCtx; 19 | } 20 | 21 | @Override 22 | public void initChannel(SocketChannel ch) { 23 | ChannelPipeline pipeline = ch.pipeline(); 24 | 25 | if (sslCtx != null) { 26 | pipeline.addLast(sslCtx.newHandler(ch.alloc())); 27 | } 28 | 29 | // Enable stream compression (you can remove these two if unnecessary) 30 | pipeline.addLast(ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP)); 31 | pipeline.addLast(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP)); 32 | 33 | // Add the number codec first, 34 | pipeline.addLast(new BigIntegerDecoder()); 35 | pipeline.addLast(new NumberEncoder()); 36 | 37 | // and then business logic. 38 | // Please note we create a handler for every new channel 39 | // because it has stateful properties. 40 | pipeline.addLast(new FactorialServerHandler()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/factorial/NumberEncoder.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.factorial; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.codec.MessageToByteEncoder; 6 | 7 | import java.math.BigInteger; 8 | 9 | /** 10 | * Encodes a {@link Number} into the binary representation prepended with 11 | * a magic number ('F' or 0x46) and a 32-bit length prefix. For example, 42 12 | * will be encoded to { 'F', 0, 0, 0, 1, 42 }. 13 | */ 14 | public class NumberEncoder extends MessageToByteEncoder { 15 | 16 | @Override 17 | protected void encode(ChannelHandlerContext ctx, Number msg, ByteBuf out) { 18 | // Convert to a BigInteger first for easier implementation. 19 | BigInteger v; 20 | if (msg instanceof BigInteger) { 21 | v = (BigInteger) msg; 22 | } else { 23 | v = new BigInteger(String.valueOf(msg)); 24 | } 25 | 26 | // Convert the number into a byte array. 27 | byte[] data = v.toByteArray(); 28 | int dataLength = data.length; 29 | 30 | // Write a message. 31 | out.writeByte((byte) 'F'); // magic number 32 | out.writeInt(dataLength); // data length 33 | out.writeBytes(data); // data 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/file/FileClientHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.netty.demo.file; 5 | 6 | import java.io.File; 7 | import java.io.FileOutputStream; 8 | 9 | import io.netty.channel.ChannelHandlerContext; 10 | import io.netty.channel.SimpleChannelInboundHandler; 11 | 12 | /** 13 | * 说明:文件客户端处理器 14 | * 15 | * @author waylau.com 2015年11月6日 16 | */ 17 | public class FileClientHandler extends SimpleChannelInboundHandler { 18 | 19 | private String dest; 20 | 21 | /** 22 | * 23 | * @param dest 文件生成路径 24 | */ 25 | public FileClientHandler(String dest) { 26 | this.dest = dest; 27 | } 28 | 29 | @Override 30 | protected void channelRead0(ChannelHandlerContext ctx, String msg) 31 | throws Exception { 32 | 33 | File file = new File(dest); 34 | if (!file.exists()) { 35 | file.createNewFile(); 36 | } 37 | 38 | FileOutputStream fos = new FileOutputStream(file); 39 | 40 | fos.write(msg.getBytes()); 41 | fos.close(); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/file/FileServerHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2018 Lilinfeng. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.waylau.netty.demo.file; 17 | 18 | import io.netty.channel.ChannelHandlerContext; 19 | import io.netty.channel.DefaultFileRegion; 20 | import io.netty.channel.FileRegion; 21 | import io.netty.channel.SimpleChannelInboundHandler; 22 | 23 | import java.io.File; 24 | import java.io.RandomAccessFile; 25 | 26 | /** 27 | * 说明:文件服务器处理器 28 | * 29 | * @author waylau.com 2015年11月5日 30 | */ 31 | public class FileServerHandler extends SimpleChannelInboundHandler { 32 | 33 | private static final String CR = System.getProperty("line.separator"); 34 | 35 | @Override 36 | protected void channelRead0(ChannelHandlerContext ctx, String msg) 37 | throws Exception { 38 | File file = new File(msg); 39 | if (file.exists()) { 40 | if (!file.isFile()) { 41 | ctx.writeAndFlush("Not a file : " + file + CR); 42 | return; 43 | } 44 | ctx.write(file + " " + file.length() + CR); 45 | RandomAccessFile randomAccessFile = new RandomAccessFile(msg, "r"); 46 | FileRegion region = new DefaultFileRegion( 47 | randomAccessFile.getChannel(), 0, randomAccessFile.length()); 48 | ctx.write(region); 49 | ctx.writeAndFlush(CR); 50 | randomAccessFile.close(); 51 | } else { 52 | ctx.writeAndFlush("File not found: " + file + CR); 53 | } 54 | 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/file/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * 说明:本包主要是要演示了文件服务器的功能. 6 | * 客户端启动时,会指定一个文件要保存的路径,本例为“D:/reciveFile.txt”。 7 | * 客户端发送文件的请求,需在控制台输入所请求文件的路径(当然为了简单演示,该文件是服务器上的文件), 8 | * 而后,服务器会将该文件传送给客户端端,客户端将文件内容写入“D:/reciveFile.txt” 9 | * 10 | * 11 | * @author waylau.com 2015年11月6日 12 | */ 13 | package com.waylau.netty.demo.file; -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/heartbeat/HeartbeatHandlerInitializer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.heartbeat; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelInitializer; 5 | import io.netty.channel.ChannelPipeline; 6 | import io.netty.handler.timeout.IdleStateHandler; 7 | 8 | import java.util.concurrent.TimeUnit; 9 | 10 | /** 11 | * Heartbeat Handler Initializer 12 | * 13 | * @since 1.0.0 2019年12月19日 14 | * @author Way Lau 15 | */ 16 | public class HeartbeatHandlerInitializer extends ChannelInitializer { 17 | 18 | private static final int READ_IDEL_TIME_OUT = 4; // 读超时 19 | private static final int WRITE_IDEL_TIME_OUT = 5;// 写超时 20 | private static final int ALL_IDEL_TIME_OUT = 7; // 所有超时 21 | 22 | @Override 23 | protected void initChannel(Channel ch) throws Exception { 24 | ChannelPipeline pipeline = ch.pipeline(); 25 | pipeline.addLast(new IdleStateHandler(READ_IDEL_TIME_OUT, 26 | WRITE_IDEL_TIME_OUT, ALL_IDEL_TIME_OUT, TimeUnit.SECONDS)); // (1) 27 | pipeline.addLast(new HeartbeatServerHandler()); // (2) 28 | } 29 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/heartbeat/HeartbeatServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.heartbeat; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelOption; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.nio.NioEventLoopGroup; 8 | import io.netty.channel.socket.nio.NioServerSocketChannel; 9 | import io.netty.handler.logging.LogLevel; 10 | import io.netty.handler.logging.LoggingHandler; 11 | 12 | /** 13 | * Heartbeat Server. 14 | * 15 | * @since 1.0.0 2019年12月19日 16 | * @author Way Lau 17 | */ 18 | public final class HeartbeatServer { 19 | 20 | static final int PORT = 8082; 21 | 22 | public static void main(String[] args) throws Exception { 23 | 24 | // 配置服务器 25 | EventLoopGroup bossGroup = new NioEventLoopGroup(1); 26 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 27 | try { 28 | ServerBootstrap b = new ServerBootstrap(); 29 | b.group(bossGroup, workerGroup) 30 | .channel(NioServerSocketChannel.class) 31 | .option(ChannelOption.SO_BACKLOG, 100) 32 | .handler(new LoggingHandler(LogLevel.INFO)) 33 | .childHandler(new HeartbeatHandlerInitializer()); 34 | 35 | // 启动 36 | ChannelFuture f = b.bind(PORT).sync(); 37 | 38 | f.channel().closeFuture().sync(); 39 | } finally { 40 | bossGroup.shutdownGracefully(); 41 | workerGroup.shutdownGracefully(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/heartbeat/HeartbeatServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.heartbeat; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.Unpooled; 5 | import io.netty.channel.ChannelFutureListener; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.ChannelInboundHandlerAdapter; 8 | import io.netty.handler.timeout.IdleState; 9 | import io.netty.handler.timeout.IdleStateEvent; 10 | import io.netty.util.CharsetUtil; 11 | 12 | 13 | /** 14 | * HeartbeatServer Handler. 15 | * 16 | * @since 1.0.0 2019年12月19日 17 | * @author Way Lau 18 | */ 19 | public class HeartbeatServerHandler extends ChannelInboundHandlerAdapter { 20 | 21 | // (1)心跳内容 22 | private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled 23 | .unreleasableBuffer(Unpooled.copiedBuffer("Heartbeat", 24 | CharsetUtil.UTF_8)); 25 | 26 | @Override 27 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) 28 | throws Exception { 29 | 30 | // (2)判断超时类型 31 | if (evt instanceof IdleStateEvent) { 32 | IdleStateEvent event = (IdleStateEvent) evt; 33 | String type = ""; 34 | if (event.state() == IdleState.READER_IDLE) { 35 | type = "read idle"; 36 | } else if (event.state() == IdleState.WRITER_IDLE) { 37 | type = "write idle"; 38 | } else if (event.state() == IdleState.ALL_IDLE) { 39 | type = "all idle"; 40 | } 41 | 42 | // (3)发送心跳 43 | ctx.writeAndFlush(HEARTBEAT_SEQUENCE.duplicate()).addListener( 44 | ChannelFutureListener.CLOSE_ON_FAILURE); 45 | 46 | System.out.println( ctx.channel().remoteAddress()+"超时类型:" + type); 47 | } else { 48 | super.userEventTriggered(ctx, evt); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/heartbeat/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 说明:本例子是一个心跳服务器程序。 3 | * 可以设置连接超时时间。如果连接超时,则服务器发送心跳消息给客户端。 4 | * 本例的客户端可以是 Telnet 程序。 5 | * 6 | * @since 1.0.0 2019年12月19日 7 | * @author Way Lau 8 | */ 9 | package com.waylau.netty.demo.heartbeat; -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/http2/client/Http2SettingsHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.http2.client; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelPromise; 5 | import io.netty.channel.SimpleChannelInboundHandler; 6 | import io.netty.handler.codec.http2.Http2Settings; 7 | 8 | import java.util.concurrent.TimeUnit; 9 | 10 | /** 11 | * Reads the first {@link Http2Settings} object and notifies a {@link io.netty.channel.ChannelPromise} 12 | * 13 | * @since 1.0.0 2019年12月29日 14 | * @author Way Lau 15 | */ 16 | public class Http2SettingsHandler extends SimpleChannelInboundHandler { 17 | private final ChannelPromise promise; 18 | 19 | /** 20 | * Create new instance 21 | * 22 | * @param promise Promise object used to notify when first settings are received 23 | */ 24 | public Http2SettingsHandler(ChannelPromise promise) { 25 | this.promise = promise; 26 | } 27 | 28 | /** 29 | * Wait for this handler to be added after the upgrade to HTTP/2, and for initial preface 30 | * handshake to complete. 31 | * 32 | * @param timeout Time to wait 33 | * @param unit {@link java.util.concurrent.TimeUnit} for {@code timeout} 34 | * @throws Exception if timeout or other failure occurs 35 | */ 36 | public void awaitSettings(long timeout, TimeUnit unit) throws Exception { 37 | if (!promise.awaitUninterruptibly(timeout, unit)) { 38 | throw new IllegalStateException("Timed out waiting for settings"); 39 | } 40 | if (!promise.isSuccess()) { 41 | throw new RuntimeException(promise.cause()); 42 | } 43 | } 44 | 45 | @Override 46 | protected void channelRead0(ChannelHandlerContext ctx, Http2Settings msg) throws Exception { 47 | promise.setSuccess(); 48 | ctx.pipeline().remove(this); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/http2/server/Http2OrHttpHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.http2.server; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.handler.codec.http.HttpObjectAggregator; 5 | import io.netty.handler.codec.http.HttpServerCodec; 6 | import io.netty.handler.ssl.ApplicationProtocolNames; 7 | import io.netty.handler.ssl.ApplicationProtocolNegotiationHandler; 8 | 9 | /** 10 | * HTTP/2 or HTTP/1.1 Handler. 11 | * 12 | * @since 1.0.0 2019年12月29日 13 | * @author Way Lau 14 | */ 15 | public class Http2OrHttpHandler extends ApplicationProtocolNegotiationHandler { 16 | 17 | private static final int MAX_CONTENT_LENGTH = 1024 * 100; 18 | 19 | protected Http2OrHttpHandler() { 20 | super(ApplicationProtocolNames.HTTP_1_1); 21 | } 22 | 23 | @Override 24 | protected void configurePipeline(ChannelHandlerContext ctx, String protocol) throws Exception { 25 | if (ApplicationProtocolNames.HTTP_2.equals(protocol)) { 26 | ctx.pipeline().addLast(new Http2ServerHandlerBuilder().build()); 27 | return; 28 | } 29 | 30 | if (ApplicationProtocolNames.HTTP_1_1.equals(protocol)) { 31 | ctx.pipeline().addLast(new HttpServerCodec(), 32 | new HttpObjectAggregator(MAX_CONTENT_LENGTH), 33 | new Http1ServerHandler("ALPN Negotiation")); 34 | return; 35 | } 36 | 37 | throw new IllegalStateException("unknown protocol: " + protocol); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/http2/server/Http2Server.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.http2.server; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelOption; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.nio.NioEventLoopGroup; 8 | import io.netty.channel.socket.nio.NioServerSocketChannel; 9 | 10 | /** 11 | * HTTP/2 Server. 12 | * 13 | * @since 1.0.0 2019年12月29日 14 | * @author Way Lau 15 | */ 16 | public class Http2Server { 17 | 18 | public static int DEFAULT_PORT = 8080; 19 | 20 | public static void main(String[] args) throws Exception { 21 | int port; 22 | 23 | try { 24 | port = Integer.parseInt(args[0]); 25 | } catch (RuntimeException ex) { 26 | port = DEFAULT_PORT; 27 | } 28 | 29 | // 多线程事件循环器 30 | EventLoopGroup bossGroup = new NioEventLoopGroup(1); // boss 31 | EventLoopGroup workerGroup = new NioEventLoopGroup(); // worker 32 | 33 | try { 34 | // 启动NIO服务的引导程序类 35 | ServerBootstrap b = new ServerBootstrap(); 36 | 37 | b.group(bossGroup, workerGroup) // 设置EventLoopGroup 38 | .channel(NioServerSocketChannel.class) // 指明新的Channel的类型 39 | .childHandler(new Http2ServerInitializer()) // 指定ChannelHandler 40 | .option(ChannelOption.SO_BACKLOG, 128) // 设置的ServerChannel的一些选项 41 | .childOption(ChannelOption.SO_KEEPALIVE, true); // 设置的ServerChannel的子Channel的选项 42 | 43 | // 绑定端口,开始接收进来的连接 44 | ChannelFuture f = b.bind(port).sync(); 45 | 46 | System.out.println("HTTP/2服务器已启动,端口:" + port); 47 | 48 | // 等待服务器 socket 关闭 。 49 | // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。 50 | f.channel().closeFuture().sync(); 51 | } finally { 52 | 53 | // 优雅的关闭 54 | workerGroup.shutdownGracefully(); 55 | bossGroup.shutdownGracefully(); 56 | } 57 | 58 | } 59 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/http2/server/Http2ServerHandlerBuilder.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.http2.server; 2 | 3 | import io.netty.handler.codec.http2.AbstractHttp2ConnectionHandlerBuilder; 4 | import io.netty.handler.codec.http2.Http2ConnectionDecoder; 5 | import io.netty.handler.codec.http2.Http2ConnectionEncoder; 6 | import io.netty.handler.codec.http2.Http2FrameLogger; 7 | import io.netty.handler.codec.http2.Http2Settings; 8 | 9 | import static io.netty.handler.logging.LogLevel.INFO; 10 | 11 | /** 12 | * Http2ServerHandler Builder. 13 | * 14 | * @since 1.0.0 2019年12月29日 15 | * @author Way Lau 16 | */ 17 | public final class Http2ServerHandlerBuilder 18 | extends AbstractHttp2ConnectionHandlerBuilder { 19 | 20 | private static final Http2FrameLogger logger = new Http2FrameLogger(INFO, Http2ServerHandler.class); 21 | 22 | public Http2ServerHandlerBuilder() { 23 | frameLogger(logger); 24 | } 25 | 26 | @Override 27 | public Http2ServerHandler build() { 28 | return super.build(); 29 | } 30 | 31 | @Override 32 | protected Http2ServerHandler build(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder, 33 | Http2Settings initialSettings) { 34 | Http2ServerHandler handler = new Http2ServerHandler(decoder, encoder, initialSettings); 35 | frameListener(handler); 36 | return handler; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/httpserver/HttpServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.httpserver; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelOption; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.nio.NioEventLoopGroup; 8 | import io.netty.channel.socket.nio.NioServerSocketChannel; 9 | 10 | /** 11 | * HTTP Server. 12 | * 13 | * @since 1.0.0 2019年12月26日 14 | * @author Way Lau 15 | */ 16 | public class HttpServer { 17 | 18 | public static int DEFAULT_PORT = 8080; 19 | 20 | public static void main(String[] args) throws Exception { 21 | int port; 22 | 23 | try { 24 | port = Integer.parseInt(args[0]); 25 | } catch (RuntimeException ex) { 26 | port = DEFAULT_PORT; 27 | } 28 | 29 | // 多线程事件循环器 30 | EventLoopGroup bossGroup = new NioEventLoopGroup(1); // boss 31 | EventLoopGroup workerGroup = new NioEventLoopGroup(); // worker 32 | 33 | try { 34 | // 启动NIO服务的引导程序类 35 | ServerBootstrap b = new ServerBootstrap(); 36 | 37 | b.group(bossGroup, workerGroup) // 设置EventLoopGroup 38 | .channel(NioServerSocketChannel.class) // 指明新的Channel的类型 39 | .childHandler(new HttpServerChannelInitializer()) // 指定ChannelHandler 40 | .option(ChannelOption.SO_BACKLOG, 128) // 设置的ServerChannel的一些选项 41 | .childOption(ChannelOption.SO_KEEPALIVE, true); // 设置的ServerChannel的子Channel的选项 42 | 43 | // 绑定端口,开始接收进来的连接 44 | ChannelFuture f = b.bind(port).sync(); 45 | 46 | System.out.println("HttpServer已启动,端口:" + port); 47 | 48 | // 等待服务器 socket 关闭 。 49 | // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。 50 | f.channel().closeFuture().sync(); 51 | } finally { 52 | 53 | // 优雅的关闭 54 | workerGroup.shutdownGracefully(); 55 | bossGroup.shutdownGracefully(); 56 | } 57 | 58 | } 59 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/httpserver/HttpServerChannelInitializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to https://waylau.com 3 | */ 4 | package com.waylau.netty.demo.httpserver; 5 | 6 | import io.netty.channel.ChannelInitializer; 7 | import io.netty.channel.socket.SocketChannel; 8 | import io.netty.handler.codec.http.HttpObjectAggregator; 9 | import io.netty.handler.codec.http.HttpServerCodec; 10 | 11 | /** 12 | * HTTP Server ChannelInitializer. 13 | * 14 | * @since 1.0.0 2019年12月26日 15 | * @author Way Lau 16 | */ 17 | public class HttpServerChannelInitializer extends ChannelInitializer { 18 | 19 | public HttpServerChannelInitializer() { 20 | 21 | } 22 | 23 | @Override 24 | protected void initChannel(SocketChannel ch) throws Exception { 25 | ch.pipeline().addLast("codec", new HttpServerCodec()); 26 | ch.pipeline().addLast("aggregator", new HttpObjectAggregator(1048576)); 27 | ch.pipeline().addLast("serverHandler", new HttpServerHandler()); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/httpserver/HttpServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.httpserver; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.Unpooled; 5 | import io.netty.channel.ChannelFutureListener; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.SimpleChannelInboundHandler; 8 | import io.netty.handler.codec.http.DefaultFullHttpResponse; 9 | import io.netty.handler.codec.http.FullHttpRequest; 10 | import io.netty.handler.codec.http.FullHttpResponse; 11 | import io.netty.handler.codec.http.HttpHeaderNames; 12 | import io.netty.handler.codec.http.HttpResponseStatus; 13 | import io.netty.handler.codec.http.HttpVersion; 14 | import io.netty.util.CharsetUtil; 15 | 16 | /** 17 | * HTPP Server Handler. 18 | * 19 | * @since 1.0.0 2019年12月26日 20 | * @author Way Lau 21 | */ 22 | public class HttpServerHandler extends SimpleChannelInboundHandler { 23 | 24 | @Override 25 | protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception { 26 | this.readRequest(msg); 27 | 28 | String sendMsg; 29 | String uri = msg.uri(); 30 | 31 | switch (uri) { 32 | case "/": 33 | sendMsg = "

Netty HTTP Server

Welcome to waylau.com!

"; 34 | break; 35 | case "/hi": 36 | sendMsg = "

Netty HTTP Server

Hello Word!

"; 37 | break; 38 | case "/love": 39 | sendMsg = "

Netty HTTP Server

I Love You!

"; 40 | break; 41 | default: 42 | sendMsg = "

Netty HTTP Server

I was lost!

"; 43 | break; 44 | } 45 | 46 | this.writeResponse(ctx, sendMsg); 47 | } 48 | 49 | private void readRequest(FullHttpRequest msg) { 50 | System.out.println("======请求行======"); 51 | System.out.println(msg.method() + " " + msg.uri() + " " + msg.protocolVersion()); 52 | 53 | System.out.println("======请求头======"); 54 | for (String name : msg.headers().names()) { 55 | System.out.println(name + ": " + msg.headers().get(name)); 56 | 57 | } 58 | 59 | System.out.println("======消息体======"); 60 | System.out.println(msg.content().toString(CharsetUtil.UTF_8)); 61 | 62 | } 63 | 64 | private void writeResponse(ChannelHandlerContext ctx, String msg) { 65 | ByteBuf bf = Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8); 66 | 67 | FullHttpResponse res = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, bf); 68 | res.headers().set(HttpHeaderNames.CONTENT_LENGTH, msg.length()); 69 | ctx.writeAndFlush(res).addListener(ChannelFutureListener.CLOSE_ON_FAILURE); 70 | } 71 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/pojo/MessageToByteTimeEncoder.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.pojo; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.codec.MessageToByteEncoder; 6 | 7 | /** 8 | * @author wangjun 9 | * @date 2020-08-08 10 | */ 11 | public class MessageToByteTimeEncoder extends MessageToByteEncoder { 12 | 13 | @Override 14 | protected void encode(ChannelHandlerContext ctx, UnixTime msg, ByteBuf out) { 15 | out.writeInt((int)msg.value()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/pojo/TimeClient.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.pojo; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelOption; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.channel.socket.nio.NioSocketChannel; 11 | 12 | public class TimeClient { 13 | 14 | public static void main(String[] args) throws Exception { 15 | 16 | String host = "127.0.0.1";// args[0]; 17 | int port = 8080;//Integer.parseInt(args[1]); 18 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 19 | 20 | try { 21 | Bootstrap b = new Bootstrap(); // (1) 22 | b.group(workerGroup); // (2) 23 | b.channel(NioSocketChannel.class); // (3) 24 | b.option(ChannelOption.SO_KEEPALIVE, true); // (4) 25 | b.handler(new ChannelInitializer() { 26 | @Override 27 | public void initChannel(SocketChannel ch) throws Exception { 28 | ch.pipeline().addLast(new TimeDecoder()); 29 | ch.pipeline().addLast(new TimeClientHandler()); 30 | } 31 | }); 32 | 33 | // 启动客户端 34 | ChannelFuture f = b.connect(host, port).sync(); // (5) 35 | 36 | // 等待连接关闭 37 | f.channel().closeFuture().sync(); 38 | } finally { 39 | workerGroup.shutdownGracefully(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/pojo/TimeClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.pojo; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelInboundHandlerAdapter; 5 | 6 | /** 7 | * @author wj89757 8 | * @date 2020-08-08 9 | */ 10 | public class TimeClientHandler extends ChannelInboundHandlerAdapter{ 11 | 12 | @Override 13 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 14 | UnixTime m = (UnixTime) msg; 15 | System.out.println(m); 16 | ctx.close(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/pojo/TimeDecoder.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.pojo; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.codec.ByteToMessageDecoder; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * TimeDecoder 处理数据拆分的问题 11 | * @author wj89757 12 | * @date 2020-08-08 13 | */ 14 | public class TimeDecoder extends ByteToMessageDecoder { 15 | 16 | @Override 17 | protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list) throws Exception { 18 | if (byteBuf.readableBytes() < 4) { 19 | return; 20 | } 21 | list.add(new UnixTime(byteBuf.readUnsignedInt())); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/pojo/TimeEncoder.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.pojo; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelOutboundHandlerAdapter; 6 | import io.netty.channel.ChannelPromise; 7 | 8 | /** 9 | * @author wj89757 10 | * @date 2020-08-08 11 | */ 12 | public class TimeEncoder extends ChannelOutboundHandlerAdapter { 13 | /** 14 | * 第一,通过 ChannelPromise,当编码后的数据被写到了通道上 Netty 可以通过这个对象标记是成功还是失败。 15 | * 第二, 我们不需要调用 cxt.flush()。因为处理器已经单独分离出了一个方法 void flush(ChannelHandlerContext cxt), 16 | * 如果像自己实现 flush() 方法内容可以自行覆盖这个方法。 17 | */ 18 | @Override 19 | public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) { 20 | UnixTime m = (UnixTime) msg; 21 | ByteBuf encoded = ctx.alloc().buffer(4); 22 | encoded.writeInt((int)m.value()); 23 | ctx.write(encoded, promise); // (1) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/pojo/TimeServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.pojo; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelOption; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.channel.socket.nio.NioServerSocketChannel; 11 | 12 | /** 13 | * 时间服务器 14 | */ 15 | public class TimeServer { 16 | 17 | private int port; 18 | 19 | public TimeServer(int port) { 20 | this.port = port; 21 | } 22 | 23 | public void run() throws Exception { 24 | EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1) 25 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 26 | try { 27 | ServerBootstrap b = new ServerBootstrap(); // (2) 28 | b.group(bossGroup, workerGroup) 29 | .channel(NioServerSocketChannel.class) // (3) 30 | .childHandler(new ChannelInitializer() { // (4) 31 | @Override 32 | public void initChannel(SocketChannel ch) throws Exception { 33 | ch.pipeline().addLast(new TimeEncoder()); 34 | ch.pipeline().addLast(new TimeServerHandler()); 35 | } 36 | }) 37 | .option(ChannelOption.SO_BACKLOG, 128) // (5) 38 | .childOption(ChannelOption.SO_KEEPALIVE, true); // (6) 39 | 40 | // 绑定端口,开始接收进来的连接 41 | ChannelFuture f = b.bind(port).sync(); // (7) 42 | 43 | // 等待服务器 socket 关闭 。 44 | // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。 45 | f.channel().closeFuture().sync(); 46 | } finally { 47 | workerGroup.shutdownGracefully(); 48 | bossGroup.shutdownGracefully(); 49 | } 50 | } 51 | 52 | public static void main(String[] args) throws Exception { 53 | int port; 54 | if (args.length > 0) { 55 | port = Integer.parseInt(args[0]); 56 | } else { 57 | port = 8080; 58 | } 59 | new TimeServer(port).run(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/pojo/TimeServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.pojo; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelFutureListener; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.ChannelInboundHandlerAdapter; 8 | 9 | /** 10 | * @author wj89757 11 | * @date 2020-08-08 12 | */ 13 | public class TimeServerHandler extends ChannelInboundHandlerAdapter { 14 | 15 | @Override 16 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 17 | ChannelFuture f = ctx.writeAndFlush(new UnixTime()); 18 | f.addListener(ChannelFutureListener.CLOSE); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/pojo/UnixTime.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.pojo; 2 | 3 | import java.util.Date; 4 | 5 | /** 6 | * @author wj89757 7 | * @date 2020-08-08 8 | */ 9 | public class UnixTime { 10 | private final long value; 11 | 12 | public UnixTime() { 13 | this(System.currentTimeMillis() / 1000L + 2208988800L); 14 | } 15 | 16 | public UnixTime(long value) { 17 | this.value = value; 18 | } 19 | 20 | public long value() { 21 | return value; 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | return new Date((value() - 2208988800L) * 1000L).toString(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/protocol/ClientTask.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.protocol; 2 | 3 | /** 4 | * 说明: 5 | * 6 | * @author waylau.com 2015年11月5日 7 | */ 8 | public class ClientTask implements Runnable { 9 | 10 | /** 11 | * 12 | */ 13 | public ClientTask() { 14 | // TODO Auto-generated constructor stub 15 | } 16 | 17 | /* (non-Javadoc) 18 | * @see java.lang.Runnable#run() 19 | */ 20 | @Override 21 | public void run() { 22 | // TODO Auto-generated method stub 23 | try { 24 | ProtocolClient client = new ProtocolClient("localhost", 8082); 25 | 26 | client.run(); 27 | 28 | 29 | } catch (InterruptedException e) { 30 | // TODO Auto-generated catch block 31 | e.printStackTrace(); 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/protocol/MsgType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.netty.demo.protocol; 5 | 6 | /** 7 | * 说明:消息类型 8 | * 9 | * @author waylau.com 2015年11月5日 10 | */ 11 | public enum MsgType { 12 | EMGW_LOGIN_REQ((byte) 0x00), 13 | EMGW_LOGIN_RES((byte) 0x01); 14 | 15 | private byte value; 16 | 17 | public byte getValue() { 18 | return value; 19 | } 20 | 21 | private MsgType(byte value) { 22 | this.value = value; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/protocol/ProtocolClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.protocol; 2 | import io.netty.channel.Channel; 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.SimpleChannelInboundHandler; 5 | 6 | /** 7 | * 说明:处理器 8 | * 9 | * @author waylau.com 2015年11月7日 10 | */ 11 | public class ProtocolClientHandler extends SimpleChannelInboundHandler { 12 | 13 | 14 | @Override 15 | protected void channelRead0(ChannelHandlerContext ctx, Object obj) 16 | throws Exception { 17 | Channel incoming = ctx.channel(); 18 | System.out.println("Server->Client:"+incoming.remoteAddress()+obj.toString()); 19 | 20 | if(obj instanceof ProtocolMsg) { 21 | ProtocolMsg msg = (ProtocolMsg)obj; 22 | System.out.println("Server->Client:"+incoming.remoteAddress()+msg.getBody()); 23 | } 24 | } 25 | @Override 26 | public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { 27 | //ctx.flush(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/protocol/ProtocolClientTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.netty.demo.protocol; 5 | 6 | import java.util.concurrent.Executor; 7 | import java.util.concurrent.Executors; 8 | 9 | /** 10 | * 说明:自定义协议客户端性能测试 11 | * 12 | * @author waylau.com 2015年11月5日 13 | */ 14 | public class ProtocolClientTest { 15 | 16 | private static final int POOL_SIZE_SEND = 100; 17 | 18 | /** 19 | * @param args 20 | * @throws InterruptedException 21 | */ 22 | public static void main(String[] args) throws InterruptedException { 23 | 24 | Executor executor = Executors.newFixedThreadPool(POOL_SIZE_SEND); 25 | for (int i = 0; i < POOL_SIZE_SEND; i++) { 26 | executor.execute(new ClientTask()); 27 | Thread.sleep(100); 28 | } 29 | 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/protocol/ProtocolDecoderDeprecation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.netty.demo.protocol; 5 | 6 | import java.util.List; 7 | 8 | import io.netty.buffer.ByteBuf; 9 | import io.netty.channel.ChannelHandlerContext; 10 | import io.netty.handler.codec.ByteToMessageDecoder; 11 | 12 | /** 13 | * 说明: 14 | * 15 | * @author waylau.com 2015年11月10日 16 | */ 17 | public class ProtocolDecoderDeprecation extends ByteToMessageDecoder { 18 | 19 | private static final int HEADER_SIZE = 10; 20 | 21 | private byte magic; // 魔数 22 | private byte msgType; // 消息类型 23 | private short reserve; // 保留字 24 | private short sn; // 序列号 25 | private int len; // 长度 26 | 27 | /** 28 | * 29 | */ 30 | public ProtocolDecoderDeprecation() { 31 | // TODO Auto-generated constructor stub 32 | } 33 | 34 | /* 35 | * (non-Javadoc) 36 | * 37 | * @see io.netty.handler.codec.ByteToMessageDecoder#decode(io.netty.channel. 38 | * ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List) 39 | */ 40 | @Override 41 | protected void decode(ChannelHandlerContext ctx, ByteBuf in, 42 | List out) throws Exception { 43 | if (in.readableBytes() < HEADER_SIZE) { 44 | return;// response header is 10 bytes 45 | } 46 | 47 | magic = in.readByte(); 48 | msgType = in.readByte(); 49 | reserve = in.readShort(); 50 | sn = in.readShort(); 51 | len = in.readInt(); 52 | 53 | if (in.readableBytes() < len) { 54 | return; // until we have the entire payload return 55 | } 56 | 57 | ByteBuf buf = in.readBytes(len); 58 | byte[] req = new byte[buf.readableBytes()]; 59 | buf.readBytes(req); 60 | String body = new String(req, "UTF-8"); 61 | ProtocolMsg msg = new ProtocolMsg(); 62 | 63 | // ProtocolBody body2 = new ProtocolBody(); 64 | // body2.setBody(body); 65 | ProtocolHeader protocolHeader = new ProtocolHeader(magic, msgType, 66 | reserve, sn, len); 67 | //msg.setProtocolBody(body2); 68 | msg.setBody(body); 69 | msg.setProtocolHeader(protocolHeader); 70 | out.add(msg); 71 | 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/protocol/ProtocolEncoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.netty.demo.protocol; 5 | 6 | import java.nio.charset.Charset; 7 | 8 | 9 | import io.netty.buffer.ByteBuf; 10 | import io.netty.channel.ChannelHandlerContext; 11 | import io.netty.handler.codec.MessageToByteEncoder; 12 | 13 | /** 14 | * 说明:编码器 15 | * 16 | * @author waylau.com 2015年11月10日 17 | */ 18 | public class ProtocolEncoder extends MessageToByteEncoder { 19 | 20 | /** 21 | * 22 | */ 23 | public ProtocolEncoder() { 24 | // TODO Auto-generated constructor stub 25 | } 26 | 27 | /** 28 | * @param outboundMessageType 29 | */ 30 | public ProtocolEncoder(Class outboundMessageType) { 31 | super(outboundMessageType); 32 | // TODO Auto-generated constructor stub 33 | } 34 | 35 | /** 36 | * @param preferDirect 37 | */ 38 | public ProtocolEncoder(boolean preferDirect) { 39 | super(preferDirect); 40 | // TODO Auto-generated constructor stub 41 | } 42 | 43 | /** 44 | * @param outboundMessageType 45 | * @param preferDirect 46 | */ 47 | public ProtocolEncoder(Class outboundMessageType, 48 | boolean preferDirect) { 49 | super(outboundMessageType, preferDirect); 50 | // TODO Auto-generated constructor stub 51 | } 52 | 53 | /* (non-Javadoc) 54 | * @see io.netty.handler.codec.MessageToByteEncoder#encode(io.netty.channel.ChannelHandlerContext, java.lang.Object, io.netty.buffer.ByteBuf) 55 | */ 56 | @Override 57 | protected void encode(ChannelHandlerContext ctx, ProtocolMsg msg, 58 | ByteBuf out) throws Exception { 59 | if (msg == null | msg.getProtocolHeader() == null) { 60 | throw new Exception("The encode message is null"); 61 | } 62 | ProtocolHeader header = msg.getProtocolHeader(); 63 | String body = msg.getBody(); 64 | byte[] bodyBytes = body.getBytes(Charset.forName("utf-8")); 65 | int bodySize = bodyBytes.length; 66 | 67 | out.writeByte(header.getMagic()); 68 | out.writeByte(header.getMsgType()); 69 | out.writeShort(header.getReserve()); 70 | out.writeShort(header.getSn()); 71 | out.writeInt(bodySize); 72 | out.writeBytes(bodyBytes); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/protocol/ProtocolHeader.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.protocol; 2 | 3 | 4 | /** 5 | * 说明:协议消息头 6 | * 7 | * @author waylau.com 2015年11月4日 8 | */ 9 | public class ProtocolHeader{ 10 | 11 | private byte magic; // 魔数 12 | private byte msgType; // 消息类型 13 | private short reserve; // 保留字 14 | private short sn; // 序列号 15 | private int len; // 长度 16 | 17 | public byte getMagic() { 18 | return magic; 19 | } 20 | public void setMagic(byte magic) { 21 | this.magic = magic; 22 | } 23 | public byte getMsgType() { 24 | return msgType; 25 | } 26 | public void setMsgType(byte msgType) { 27 | this.msgType = msgType; 28 | } 29 | public short getReserve() { 30 | return reserve; 31 | } 32 | public void setReserve(short reserve) { 33 | this.reserve = reserve; 34 | } 35 | public short getSn() { 36 | return sn; 37 | } 38 | public void setSn(short sn) { 39 | this.sn = sn; 40 | } 41 | public int getLen() { 42 | return len; 43 | } 44 | public void setLen(int len) { 45 | this.len = len; 46 | } 47 | public ProtocolHeader() { 48 | } 49 | /** 50 | * 51 | */ 52 | public ProtocolHeader(byte magic, byte msgType,short reserve,short sn,int len) { 53 | this.magic = magic; 54 | this.msgType = msgType; 55 | this.reserve = reserve; 56 | this.sn = sn; 57 | this.len = len; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/protocol/ProtocolMsg.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.protocol; 2 | 3 | /** 4 | * 说明:消息对象 5 | * 6 | * @author waylau.com 2015年11月5日 7 | */ 8 | public class ProtocolMsg { 9 | 10 | private ProtocolHeader protocolHeader = new ProtocolHeader(); 11 | private String body; 12 | 13 | public String getBody() { 14 | return body; 15 | } 16 | 17 | public void setBody(String body) { 18 | this.body = body; 19 | } 20 | 21 | 22 | /** 23 | * 24 | */ 25 | public ProtocolMsg() { 26 | // TODO Auto-generated constructor stub 27 | } 28 | 29 | public ProtocolHeader getProtocolHeader() { 30 | return protocolHeader; 31 | } 32 | 33 | public void setProtocolHeader(ProtocolHeader protocolHeader) { 34 | this.protocolHeader = protocolHeader; 35 | } 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/protocol/ProtocolServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.protocol; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.SimpleChannelInboundHandler; 6 | 7 | /** 8 | * 说明:处理器 9 | * 10 | * @author waylau.com 2015年11月7日 11 | */ 12 | public class ProtocolServerHandler extends SimpleChannelInboundHandler { 13 | 14 | 15 | @Override 16 | protected void channelRead0(ChannelHandlerContext ctx, Object obj) 17 | throws Exception { 18 | Channel incoming = ctx.channel(); 19 | 20 | if(obj instanceof ProtocolMsg) { 21 | ProtocolMsg msg = (ProtocolMsg)obj; 22 | System.out.println("Client->Server:"+incoming.remoteAddress()+msg.getBody()); 23 | incoming.write(obj); 24 | } 25 | } 26 | 27 | @Override 28 | public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { 29 | ctx.flush(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/protocol/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 说明:该包下的例子,主要是实现了自定义二进制协议 3 | * 4 | * @author waylau.com 2015年11月4日 5 | */ 6 | package com.waylau.netty.demo.protocol; 7 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/protocol/消息格式.md: -------------------------------------------------------------------------------- 1 | ## 消息格式 2 | 3 | 类型 | 名称 | 字节序列 | 取值范围 | 备注 4 | --- | ----- | ---------| --------- |---- 5 | 消息头 | magic | 0 |0x80、0x81 |帧头 6 | 消息头 | msgType | 1 |0x00-0xff |消息类型 7 | 消息头 | reserve | 2-3 |0x00 |保留字,以备扩展 8 | 消息头 | sn |4-5 |0-32767 |序列号。是一个事务标识,从0开始,每次递增1,响应消息中的序列号是从请求消息中拷贝来的。当序列号达到最大值时(32767),则又从0开始。 9 | 消息头 | len |6-9 |0-2147483647 |消息体长度。 10 | 消息体 | body |变长 |0- |消息体。格式和消息类型相关,不同的消息类型有不同的消息体格式。消息大小不应超过2G 11 | 12 | 13 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/securechat/SecureChatClient.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.securechat; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.Channel; 5 | import io.netty.channel.ChannelFuture; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.nio.NioEventLoopGroup; 8 | import io.netty.channel.socket.nio.NioSocketChannel; 9 | import io.netty.handler.ssl.SslContext; 10 | import io.netty.handler.ssl.util.InsecureTrustManagerFactory; 11 | 12 | import java.io.BufferedReader; 13 | import java.io.InputStreamReader; 14 | 15 | /** 16 | * Simple SSL chat client 17 | */ 18 | public final class SecureChatClient { 19 | 20 | static final String HOST = System.getProperty("host", "127.0.0.1"); 21 | static final int PORT = Integer.parseInt(System.getProperty("port", "8992")); 22 | 23 | public static void main(String[] args) throws Exception { 24 | // Configure SSL. 25 | final SslContext sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE); 26 | 27 | EventLoopGroup group = new NioEventLoopGroup(); 28 | try { 29 | Bootstrap b = new Bootstrap(); 30 | b.group(group) 31 | .channel(NioSocketChannel.class) 32 | .handler(new SecureChatClientInitializer(sslCtx)); 33 | 34 | // Start the connection attempt. 35 | Channel ch = b.connect(HOST, PORT).sync().channel(); 36 | 37 | // Read commands from the stdin. 38 | ChannelFuture lastWriteFuture = null; 39 | BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 40 | for (;;) { 41 | String line = in.readLine(); 42 | if (line == null) { 43 | break; 44 | } 45 | 46 | // Sends the received line to the server. 47 | lastWriteFuture = ch.writeAndFlush(line + "\r\n"); 48 | 49 | // If user typed the 'bye' command, wait until the server closes 50 | // the connection. 51 | if ("bye".equals(line.toLowerCase())) { 52 | ch.closeFuture().sync(); 53 | break; 54 | } 55 | } 56 | 57 | // Wait until all messages are flushed before closing the channel. 58 | if (lastWriteFuture != null) { 59 | lastWriteFuture.sync(); 60 | } 61 | } finally { 62 | // The connection is closed automatically on shutdown. 63 | group.shutdownGracefully(); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/securechat/SecureChatClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.securechat; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.SimpleChannelInboundHandler; 5 | 6 | /** 7 | * Handles a client-side channel. 8 | */ 9 | public class SecureChatClientHandler extends SimpleChannelInboundHandler { 10 | 11 | public void messageReceived(ChannelHandlerContext ctx, String msg) { 12 | System.err.println(msg); 13 | } 14 | 15 | @Override 16 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 17 | cause.printStackTrace(); 18 | ctx.close(); 19 | } 20 | 21 | @Override 22 | protected void channelRead0(ChannelHandlerContext ctx, String msg) 23 | throws Exception { 24 | // TODO Auto-generated method stub 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/securechat/SecureChatClientInitializer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.securechat; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.DelimiterBasedFrameDecoder; 7 | import io.netty.handler.codec.Delimiters; 8 | import io.netty.handler.codec.string.StringDecoder; 9 | import io.netty.handler.codec.string.StringEncoder; 10 | import io.netty.handler.ssl.SslContext; 11 | 12 | /** 13 | * Creates a newly configured {@link ChannelPipeline} for a new channel. 14 | */ 15 | public class SecureChatClientInitializer extends ChannelInitializer { 16 | 17 | private final SslContext sslCtx; 18 | 19 | public SecureChatClientInitializer(SslContext sslCtx) { 20 | this.sslCtx = sslCtx; 21 | } 22 | 23 | @Override 24 | public void initChannel(SocketChannel ch) throws Exception { 25 | ChannelPipeline pipeline = ch.pipeline(); 26 | 27 | // Add SSL handler first to encrypt and decrypt everything. 28 | // In this example, we use a bogus certificate in the server side 29 | // and accept any invalid certificates in the client side. 30 | // You will need something more complicated to identify both 31 | // and server in the real world. 32 | pipeline.addLast(sslCtx.newHandler(ch.alloc(), SecureChatClient.HOST, SecureChatClient.PORT)); 33 | 34 | // On top of the SSL handler, add the text line codec. 35 | pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); 36 | pipeline.addLast(new StringDecoder()); 37 | pipeline.addLast(new StringEncoder()); 38 | 39 | // and then business logic. 40 | pipeline.addLast(new SecureChatClientHandler()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/securechat/SecureChatServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.securechat; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.EventLoopGroup; 5 | import io.netty.channel.nio.NioEventLoopGroup; 6 | import io.netty.channel.socket.nio.NioServerSocketChannel; 7 | import io.netty.handler.logging.LogLevel; 8 | import io.netty.handler.logging.LoggingHandler; 9 | import io.netty.handler.ssl.SslContext; 10 | import io.netty.handler.ssl.util.SelfSignedCertificate; 11 | 12 | /** 13 | * Simple SSL chat server 14 | */ 15 | public final class SecureChatServer { 16 | 17 | static final int PORT = Integer.parseInt(System.getProperty("port", "8992")); 18 | 19 | public static void main(String[] args) throws Exception { 20 | SelfSignedCertificate ssc = new SelfSignedCertificate(); 21 | SslContext sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey()); 22 | 23 | EventLoopGroup bossGroup = new NioEventLoopGroup(1); 24 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 25 | try { 26 | ServerBootstrap b = new ServerBootstrap(); 27 | b.group(bossGroup, workerGroup) 28 | .channel(NioServerSocketChannel.class) 29 | .handler(new LoggingHandler(LogLevel.INFO)) 30 | .childHandler(new SecureChatServerInitializer(sslCtx)); 31 | 32 | b.bind(PORT).sync().channel().closeFuture().sync(); 33 | } finally { 34 | bossGroup.shutdownGracefully(); 35 | workerGroup.shutdownGracefully(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/securechat/SecureChatServerInitializer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.securechat; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.DelimiterBasedFrameDecoder; 7 | import io.netty.handler.codec.Delimiters; 8 | import io.netty.handler.codec.string.StringDecoder; 9 | import io.netty.handler.codec.string.StringEncoder; 10 | import io.netty.handler.ssl.SslContext; 11 | 12 | /** 13 | * Creates a newly configured {@link ChannelPipeline} for a new channel. 14 | */ 15 | public class SecureChatServerInitializer extends ChannelInitializer { 16 | 17 | private final SslContext sslCtx; 18 | 19 | public SecureChatServerInitializer(SslContext sslCtx) { 20 | this.sslCtx = sslCtx; 21 | } 22 | 23 | @Override 24 | public void initChannel(SocketChannel ch) throws Exception { 25 | ChannelPipeline pipeline = ch.pipeline(); 26 | 27 | // Add SSL handler first to encrypt and decrypt everything. 28 | // In this example, we use a bogus certificate in the server side 29 | // and accept any invalid certificates in the client side. 30 | // You will need something more complicated to identify both 31 | // and server in the real world. 32 | pipeline.addLast(sslCtx.newHandler(ch.alloc())); 33 | 34 | // On top of the SSL handler, add the text line codec. 35 | pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); 36 | pipeline.addLast(new StringDecoder()); 37 | pipeline.addLast(new StringEncoder()); 38 | 39 | // and then business logic. 40 | pipeline.addLast(new SecureChatServerHandler()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/secureecho/EchoClient.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.secureecho; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | import java.net.UnknownHostException; 7 | import java.nio.ByteBuffer; 8 | 9 | import io.netty.bootstrap.Bootstrap; 10 | import io.netty.buffer.ByteBuf; 11 | import io.netty.buffer.Unpooled; 12 | import io.netty.channel.Channel; 13 | import io.netty.channel.ChannelFuture; 14 | import io.netty.channel.ChannelOption; 15 | import io.netty.channel.EventLoopGroup; 16 | import io.netty.channel.nio.NioEventLoopGroup; 17 | import io.netty.channel.socket.nio.NioSocketChannel; 18 | 19 | /** 20 | * Echo Client. 21 | * 22 | * @since 1.0.0 2019年10月2日 23 | * @author Way Lau 24 | */ 25 | public final class EchoClient { 26 | 27 | public static void main(String[] args) throws Exception { 28 | if (args.length != 2) { 29 | System.err.println("用法: java EchoClient "); 30 | System.exit(1); 31 | } 32 | 33 | String hostName = args[0]; 34 | int portNumber = Integer.parseInt(args[1]); 35 | 36 | // 配置客户端 37 | EventLoopGroup group = new NioEventLoopGroup(); 38 | try { 39 | Bootstrap b = new Bootstrap(); 40 | b.group(group) 41 | .channel(NioSocketChannel.class) 42 | .option(ChannelOption.TCP_NODELAY, true) 43 | .handler(new EchoClientChannelInitializer()); 44 | 45 | // 连接到服务器 46 | ChannelFuture f = b.connect(hostName, portNumber).sync(); 47 | 48 | Channel channel = f.channel(); 49 | ByteBuffer writeBuffer = ByteBuffer.allocate(32); 50 | try (BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in))) { 51 | String userInput; 52 | while ((userInput = stdIn.readLine()) != null) { 53 | writeBuffer.put(userInput.getBytes()); 54 | writeBuffer.flip(); 55 | writeBuffer.rewind(); 56 | 57 | // 转为ByteBuf 58 | ByteBuf buf = Unpooled.copiedBuffer(writeBuffer); 59 | 60 | // 写消息到管道 61 | channel.writeAndFlush(buf); 62 | 63 | // 清理缓冲区 64 | writeBuffer.clear(); 65 | } 66 | } catch (UnknownHostException e) { 67 | System.err.println("不明主机,主机名为: " + hostName); 68 | System.exit(1); 69 | } catch (IOException e) { 70 | System.err.println("不能从主机中获取I/O,主机名为:" + hostName); 71 | System.exit(1); 72 | } 73 | } finally { 74 | 75 | // 优雅的关闭 76 | group.shutdownGracefully(); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/secureecho/EchoClientChannelInitializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to https://waylau.com 3 | */ 4 | package com.waylau.netty.demo.secureecho; 5 | 6 | import javax.net.ssl.SSLEngine; 7 | 8 | import io.netty.channel.ChannelInitializer; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.handler.ssl.SslHandler; 11 | 12 | /** 13 | * Echo Client ChannelInitializer. 14 | * 15 | * @since 1.0.0 2019年12月25日 16 | * @author Way Lau 17 | */ 18 | public class EchoClientChannelInitializer extends ChannelInitializer { 19 | 20 | @Override 21 | protected void initChannel(SocketChannel ch) throws Exception { 22 | 23 | // 先添加SslHandler 24 | String pkPath = System.getProperties().getProperty("user.dir") 25 | + "/src/main/resources/ssl/nettyClient.jks"; 26 | String password = "defaultPass"; 27 | SSLEngine engine = SslContextFactory.getServerContext(pkPath, pkPath, password).createSSLEngine(); 28 | engine.setUseClientMode(true); // 设置为服务器模式 29 | engine.setNeedClientAuth(true); // 需要客户端认证 30 | ch.pipeline().addLast(new SslHandler(engine)); 31 | 32 | // 再添加其他ChannelHandler 33 | ch.pipeline().addLast(new EchoClientHandler()); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/secureecho/EchoClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.secureecho; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelInboundHandlerAdapter; 6 | import io.netty.util.CharsetUtil; 7 | 8 | /** 9 | * Echo Client Handler. 10 | * 11 | * @since 1.0.0 2019年10月2日 12 | * @author Way Lau 13 | */ 14 | public class EchoClientHandler extends ChannelInboundHandlerAdapter { 15 | @Override 16 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 17 | // 接收服务器的信息并打印到控制台 18 | ByteBuf in = (ByteBuf) msg; 19 | System.out.println(ctx.channel().remoteAddress() + " -> Client :" + 20 | in.toString(CharsetUtil.UTF_8)); 21 | 22 | } 23 | 24 | @Override 25 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 26 | 27 | // 当出现异常就关闭连接 28 | cause.printStackTrace(); 29 | ctx.close(); 30 | } 31 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/secureecho/EchoServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.secureecho; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelOption; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.nio.NioEventLoopGroup; 8 | import io.netty.channel.socket.nio.NioServerSocketChannel; 9 | 10 | /** 11 | * Echo Server. 12 | * 13 | * @since 1.0.0 2019年10月2日 14 | * @author Way Lau 15 | */ 16 | public class EchoServer { 17 | 18 | public static int DEFAULT_PORT = 7; 19 | 20 | public static void main(String[] args) throws Exception { 21 | int port; 22 | 23 | try { 24 | port = Integer.parseInt(args[0]); 25 | } catch (RuntimeException ex) { 26 | port = DEFAULT_PORT; 27 | } 28 | 29 | // 多线程事件循环器 30 | EventLoopGroup bossGroup = new NioEventLoopGroup(1); // boss 31 | EventLoopGroup workerGroup = new NioEventLoopGroup(); // worker 32 | 33 | try { 34 | // 启动NIO服务的引导程序类 35 | ServerBootstrap b = new ServerBootstrap(); 36 | 37 | b.group(bossGroup, workerGroup) // 设置EventLoopGroup 38 | .channel(NioServerSocketChannel.class) // 指明新的Channel的类型 39 | .childHandler(new EchoServerChannelInitializer()) // 指定ChannelHandler 40 | .option(ChannelOption.SO_BACKLOG, 128) // 设置的ServerChannel的一些选项 41 | .childOption(ChannelOption.SO_KEEPALIVE, true); // 设置的ServerChannel的子Channel的选项 42 | 43 | // 绑定端口,开始接收进来的连接 44 | ChannelFuture f = b.bind(port).sync(); 45 | 46 | System.out.println("EchoServer已启动,端口:" + port); 47 | 48 | // 等待服务器 socket 关闭 。 49 | // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。 50 | f.channel().closeFuture().sync(); 51 | } finally { 52 | 53 | // 优雅的关闭 54 | workerGroup.shutdownGracefully(); 55 | bossGroup.shutdownGracefully(); 56 | } 57 | 58 | } 59 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/secureecho/EchoServerChannelInitializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to https://waylau.com 3 | */ 4 | package com.waylau.netty.demo.secureecho; 5 | 6 | import javax.net.ssl.SSLEngine; 7 | 8 | import io.netty.channel.ChannelInitializer; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.handler.ssl.SslHandler; 11 | 12 | /** 13 | * Echo Server ChannelInitializer. 14 | * 15 | * @since 1.0.0 2019年12月25日 16 | * @author Way Lau 17 | */ 18 | public class EchoServerChannelInitializer extends ChannelInitializer { 19 | 20 | @Override 21 | protected void initChannel(SocketChannel ch) throws Exception { 22 | 23 | // 先添加SslHandler 24 | String pkPath = System.getProperties().getProperty("user.dir") + "/src/main/resources/ssl/nettyServer.jks"; 25 | String password = "defaultPass"; 26 | SSLEngine engine = SslContextFactory.getServerContext(pkPath, pkPath, password).createSSLEngine(); 27 | engine.setUseClientMode(false); // 设置为服务器模式 28 | engine.setNeedClientAuth(true); // 需要客户端认证 29 | ch.pipeline().addLast(new SslHandler(engine)); 30 | 31 | // 再添加其他ChannelHandler 32 | ch.pipeline().addLast(new EchoServerHandler()); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/secureecho/EchoServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.secureecho; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelInboundHandlerAdapter; 6 | import io.netty.util.CharsetUtil; 7 | 8 | /** 9 | * Echo Server Handler. 10 | * 11 | * @since 1.0.0 2019年12月25日 12 | * @author Way Lau 13 | */ 14 | public class EchoServerHandler extends ChannelInboundHandlerAdapter { 15 | 16 | @Override 17 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 18 | // 接收客户端的信息并打印到控制台 19 | ByteBuf in = (ByteBuf)msg; 20 | System.out.println(ctx.channel().remoteAddress() + " -> Server :" + 21 | in.toString(CharsetUtil.UTF_8)); 22 | 23 | // 写消息到管道 24 | ctx.write(msg);// 写消息 25 | ctx.flush(); // 刷新消息 26 | } 27 | 28 | @Override 29 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 30 | 31 | // 当出现异常就关闭连接 32 | cause.printStackTrace(); 33 | ctx.close(); 34 | } 35 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/simplechat/SimpleChatClient.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.simplechat; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.Channel; 5 | import io.netty.channel.EventLoopGroup; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import io.netty.channel.socket.nio.NioSocketChannel; 8 | 9 | import java.io.BufferedReader; 10 | import java.io.InputStreamReader; 11 | 12 | 13 | /** 14 | * 简单聊天服务器-客户端 15 | * 16 | * @author waylau.com 17 | * @date 2015-2-26 18 | */ 19 | public class SimpleChatClient { 20 | 21 | public static void main(String[] args) throws Exception{ 22 | new SimpleChatClient("localhost", 8080).run(); 23 | } 24 | 25 | private final String host; 26 | private final int port; 27 | 28 | public SimpleChatClient(String host, int port){ 29 | this.host = host; 30 | this.port = port; 31 | } 32 | 33 | public void run() throws Exception{ 34 | EventLoopGroup group = new NioEventLoopGroup(); 35 | try { 36 | Bootstrap bootstrap = new Bootstrap() 37 | .group(group) 38 | .channel(NioSocketChannel.class) 39 | .handler(new SimpleChatClientInitializer()); 40 | Channel channel = bootstrap.connect(host, port).sync().channel(); 41 | BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 42 | while(true){ 43 | channel.writeAndFlush(in.readLine() + "\r\n"); 44 | } 45 | } catch (Exception e) { 46 | e.printStackTrace(); 47 | } finally { 48 | group.shutdownGracefully(); 49 | } 50 | 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/simplechat/SimpleChatClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.simplechat; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.SimpleChannelInboundHandler; 5 | 6 | /** 7 | * 客户端 channel 8 | * 9 | * @author waylau.com 10 | * @date 2015-2-26 11 | */ 12 | public class SimpleChatClientHandler extends SimpleChannelInboundHandler { 13 | @Override 14 | protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception { 15 | System.out.println(s); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/simplechat/SimpleChatClientInitializer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.simplechat; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.DelimiterBasedFrameDecoder; 7 | import io.netty.handler.codec.Delimiters; 8 | import io.netty.handler.codec.string.StringDecoder; 9 | import io.netty.handler.codec.string.StringEncoder; 10 | 11 | 12 | /** 13 | * 客户端 ChannelInitializer 14 | * 15 | * @author waylau.com 16 | * @date 2015-2-26 17 | */ 18 | public class SimpleChatClientInitializer extends ChannelInitializer { 19 | 20 | @Override 21 | public void initChannel(SocketChannel ch) throws Exception { 22 | ChannelPipeline pipeline = ch.pipeline(); 23 | 24 | pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); 25 | pipeline.addLast("decoder", new StringDecoder()); 26 | pipeline.addLast("encoder", new StringEncoder()); 27 | pipeline.addLast("handler", new SimpleChatClientHandler()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/simplechat/SimpleChatServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.simplechat; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelOption; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.nio.NioEventLoopGroup; 8 | import io.netty.channel.socket.nio.NioServerSocketChannel; 9 | 10 | /** 11 | * 简单聊天服务器-服务端 12 | * 13 | * @author waylau.com 14 | * @date 2015-2-16 15 | */ 16 | public class SimpleChatServer { 17 | 18 | private int port; 19 | 20 | public SimpleChatServer(int port) { 21 | this.port = port; 22 | } 23 | 24 | public void run() throws Exception { 25 | 26 | EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1) 27 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 28 | try { 29 | ServerBootstrap b = new ServerBootstrap(); // (2) 30 | b.group(bossGroup, workerGroup) 31 | .channel(NioServerSocketChannel.class) // (3) 32 | .childHandler(new SimpleChatServerInitializer()) //(4) 33 | .option(ChannelOption.SO_BACKLOG, 128) // (5) 34 | .childOption(ChannelOption.SO_KEEPALIVE, true); // (6) 35 | 36 | System.out.println("SimpleChatServer 启动了"); 37 | 38 | // 绑定端口,开始接收进来的连接 39 | ChannelFuture f = b.bind(port).sync(); // (7) 40 | 41 | // 等待服务器 socket 关闭 。 42 | // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。 43 | f.channel().closeFuture().sync(); 44 | 45 | } finally { 46 | workerGroup.shutdownGracefully(); 47 | bossGroup.shutdownGracefully(); 48 | 49 | System.out.println("SimpleChatServer 关闭了"); 50 | } 51 | } 52 | 53 | public static void main(String[] args) throws Exception { 54 | int port; 55 | if (args.length > 0) { 56 | port = Integer.parseInt(args[0]); 57 | } else { 58 | port = 8080; 59 | } 60 | new SimpleChatServer(port).run(); 61 | 62 | } 63 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/simplechat/SimpleChatServerInitializer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.simplechat; 2 | 3 | 4 | import io.netty.channel.ChannelInitializer; 5 | import io.netty.channel.ChannelPipeline; 6 | import io.netty.channel.socket.SocketChannel; 7 | import io.netty.handler.codec.DelimiterBasedFrameDecoder; 8 | import io.netty.handler.codec.Delimiters; 9 | import io.netty.handler.codec.string.StringDecoder; 10 | import io.netty.handler.codec.string.StringEncoder; 11 | 12 | /** 13 | * 服务端 ChannelInitializer 14 | * 15 | * @author waylau.com 16 | * @date 2015-2-26 17 | */ 18 | public class SimpleChatServerInitializer extends 19 | ChannelInitializer { 20 | 21 | @Override 22 | public void initChannel(SocketChannel ch) throws Exception { 23 | ChannelPipeline pipeline = ch.pipeline(); 24 | 25 | pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); 26 | pipeline.addLast("decoder", new StringDecoder()); 27 | pipeline.addLast("encoder", new StringEncoder()); 28 | pipeline.addLast("handler", new SimpleChatServerHandler()); 29 | 30 | System.out.println("SimpleChatClient:"+ch.remoteAddress() +"连接上"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/telnet/TelnetClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.telnet; 2 | 3 | import io.netty.channel.ChannelHandler.Sharable; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.SimpleChannelInboundHandler; 6 | 7 | /** 8 | * Handles a client-side channel. 9 | */ 10 | @Sharable 11 | public class TelnetClientHandler extends SimpleChannelInboundHandler { 12 | 13 | protected void messageReceived(ChannelHandlerContext ctx, String msg) { 14 | System.err.println(msg); 15 | } 16 | 17 | @Override 18 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 19 | cause.printStackTrace(); 20 | ctx.close(); 21 | } 22 | 23 | @Override 24 | protected void channelRead0(ChannelHandlerContext ctx, String msg) 25 | throws Exception { 26 | // TODO Auto-generated method stub 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/telnet/TelnetClientInitializer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.telnet; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.DelimiterBasedFrameDecoder; 7 | import io.netty.handler.codec.Delimiters; 8 | import io.netty.handler.codec.string.StringDecoder; 9 | import io.netty.handler.codec.string.StringEncoder; 10 | import io.netty.handler.ssl.SslContext; 11 | 12 | /** 13 | * Creates a newly configured {@link ChannelPipeline} for a new channel. 14 | */ 15 | public class TelnetClientInitializer extends ChannelInitializer { 16 | 17 | private static final StringDecoder DECODER = new StringDecoder(); 18 | private static final StringEncoder ENCODER = new StringEncoder(); 19 | 20 | private static final TelnetClientHandler CLIENT_HANDLER = new TelnetClientHandler(); 21 | 22 | private final SslContext sslCtx; 23 | 24 | public TelnetClientInitializer(SslContext sslCtx) { 25 | this.sslCtx = sslCtx; 26 | } 27 | 28 | @Override 29 | public void initChannel(SocketChannel ch) { 30 | ChannelPipeline pipeline = ch.pipeline(); 31 | 32 | if (sslCtx != null) { 33 | pipeline.addLast(sslCtx.newHandler(ch.alloc(), TelnetClient.HOST, TelnetClient.PORT)); 34 | } 35 | 36 | // Add the text line codec combination first, 37 | pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); 38 | pipeline.addLast(DECODER); 39 | pipeline.addLast(ENCODER); 40 | 41 | // and then business logic. 42 | pipeline.addLast(CLIENT_HANDLER); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/telnet/TelnetServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.telnet; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.EventLoopGroup; 5 | import io.netty.channel.nio.NioEventLoopGroup; 6 | import io.netty.channel.socket.nio.NioServerSocketChannel; 7 | import io.netty.handler.logging.LogLevel; 8 | import io.netty.handler.logging.LoggingHandler; 9 | import io.netty.handler.ssl.SslContext; 10 | import io.netty.handler.ssl.util.SelfSignedCertificate; 11 | 12 | /** 13 | * Simplistic telnet server. 14 | */ 15 | public final class TelnetServer { 16 | 17 | static final boolean SSL = System.getProperty("ssl") != null; 18 | static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8992" : "8023")); 19 | 20 | public static void main(String[] args) throws Exception { 21 | // Configure SSL. 22 | final SslContext sslCtx; 23 | if (SSL) { 24 | SelfSignedCertificate ssc = new SelfSignedCertificate(); 25 | sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey()); 26 | } else { 27 | sslCtx = null; 28 | } 29 | 30 | EventLoopGroup bossGroup = new NioEventLoopGroup(1); 31 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 32 | try { 33 | ServerBootstrap b = new ServerBootstrap(); 34 | b.group(bossGroup, workerGroup) 35 | .channel(NioServerSocketChannel.class) 36 | .handler(new LoggingHandler(LogLevel.INFO)) 37 | .childHandler(new TelnetServerInitializer(sslCtx)); 38 | 39 | b.bind(PORT).sync().channel().closeFuture().sync(); 40 | } finally { 41 | bossGroup.shutdownGracefully(); 42 | workerGroup.shutdownGracefully(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/telnet/TelnetServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.telnet; 2 | 3 | import io.netty.channel.ChannelFuture; 4 | import io.netty.channel.ChannelFutureListener; 5 | import io.netty.channel.ChannelHandler.Sharable; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.SimpleChannelInboundHandler; 8 | 9 | import java.net.InetAddress; 10 | import java.util.Date; 11 | 12 | /** 13 | * Handles a server-side channel. 14 | */ 15 | @Sharable 16 | public class TelnetServerHandler extends SimpleChannelInboundHandler { 17 | 18 | @Override 19 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 20 | // Send greeting for a new connection. 21 | ctx.write("Welcome to " + InetAddress.getLocalHost().getHostName() + "!\r\n"); 22 | ctx.write("It is " + new Date() + " now.\r\n"); 23 | ctx.flush(); 24 | } 25 | 26 | public void messageReceived(ChannelHandlerContext ctx, String request) { 27 | // Generate and write a response. 28 | String response; 29 | boolean close = false; 30 | if (request.isEmpty()) { 31 | response = "Please type something.\r\n"; 32 | } else if ("bye".equals(request.toLowerCase())) { 33 | response = "Have a good day!\r\n"; 34 | close = true; 35 | } else { 36 | response = "Did you say '" + request + "'?\r\n"; 37 | } 38 | 39 | // We do not need to write a ChannelBuffer here. 40 | // We know the encoder inserted at TelnetPipelineFactory will do the conversion. 41 | ChannelFuture future = ctx.write(response); 42 | 43 | // Close the connection after sending 'Have a good day!' 44 | // if the client has sent 'bye'. 45 | if (close) { 46 | future.addListener(ChannelFutureListener.CLOSE); 47 | } 48 | } 49 | 50 | @Override 51 | public void channelReadComplete(ChannelHandlerContext ctx) { 52 | ctx.flush(); 53 | } 54 | 55 | @Override 56 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 57 | cause.printStackTrace(); 58 | ctx.close(); 59 | } 60 | 61 | @Override 62 | protected void channelRead0(ChannelHandlerContext ctx, String msg) 63 | throws Exception { 64 | // TODO Auto-generated method stub 65 | 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/telnet/TelnetServerInitializer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.telnet; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.DelimiterBasedFrameDecoder; 7 | import io.netty.handler.codec.Delimiters; 8 | import io.netty.handler.codec.string.StringDecoder; 9 | import io.netty.handler.codec.string.StringEncoder; 10 | import io.netty.handler.ssl.SslContext; 11 | 12 | /** 13 | * Creates a newly configured {@link ChannelPipeline} for a new channel. 14 | */ 15 | public class TelnetServerInitializer extends ChannelInitializer { 16 | 17 | private static final StringDecoder DECODER = new StringDecoder(); 18 | private static final StringEncoder ENCODER = new StringEncoder(); 19 | 20 | private static final TelnetServerHandler SERVER_HANDLER = new TelnetServerHandler(); 21 | 22 | private final SslContext sslCtx; 23 | 24 | public TelnetServerInitializer(SslContext sslCtx) { 25 | this.sslCtx = sslCtx; 26 | } 27 | 28 | @Override 29 | public void initChannel(SocketChannel ch) throws Exception { 30 | ChannelPipeline pipeline = ch.pipeline(); 31 | 32 | if (sslCtx != null) { 33 | pipeline.addLast(sslCtx.newHandler(ch.alloc())); 34 | } 35 | 36 | // Add the text line codec combination first, 37 | pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); 38 | // the encoder and decoder are static as these are sharable 39 | pipeline.addLast(DECODER); 40 | pipeline.addLast(ENCODER); 41 | 42 | // and then business logic. 43 | pipeline.addLast(SERVER_HANDLER); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/time/TimeClient.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.time; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelOption; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.channel.socket.nio.NioSocketChannel; 11 | 12 | /** 13 | * Time Client. 14 | * 15 | * @since 1.0.0 2019年10月7日 16 | * @author Way Lau 17 | */ 18 | public class TimeClient { 19 | 20 | public static void main(String[] args) throws Exception { 21 | 22 | String host = "127.0.0.1";// args[0]; 23 | int port = 8080;//Integer.parseInt(args[1]); 24 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 25 | 26 | try { 27 | Bootstrap b = new Bootstrap(); // (1) 28 | b.group(workerGroup); // (2) 29 | b.channel(NioSocketChannel.class); // (3) 30 | b.option(ChannelOption.SO_KEEPALIVE, true); // (4) 31 | b.handler(new ChannelInitializer() { 32 | @Override 33 | public void initChannel(SocketChannel ch) throws Exception { 34 | ch.pipeline().addLast(new TimeClientHandler()); 35 | } 36 | }); 37 | 38 | // 启动客户端 39 | ChannelFuture f = b.connect(host, port).sync(); // (5) 40 | 41 | // 等待连接关闭 42 | f.channel().closeFuture().sync(); 43 | } finally { 44 | workerGroup.shutdownGracefully(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/time/TimeClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.time; 2 | 3 | import java.util.Date; 4 | 5 | import io.netty.buffer.ByteBuf; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.ChannelInboundHandlerAdapter; 8 | 9 | /** 10 | * Time Client Handler. 11 | * 12 | * @since 1.0.0 2019年10月7日 13 | * @author Way Lau 14 | */ 15 | public class TimeClientHandler extends ChannelInboundHandlerAdapter { 16 | 17 | @Override 18 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 19 | ByteBuf m = (ByteBuf) msg; // (1) 20 | try { 21 | long currentTimeMillis = (m.readUnsignedInt() - 2208988800L) * 1000L; 22 | System.out.println(new Date(currentTimeMillis)); 23 | ctx.close(); 24 | } finally { 25 | m.release(); 26 | } 27 | } 28 | 29 | @Override 30 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 31 | cause.printStackTrace(); 32 | ctx.close(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/time/TimeServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.time; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelOption; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.channel.socket.nio.NioServerSocketChannel; 11 | 12 | /** 13 | * Time Server. 14 | * 15 | * @since 1.0.0 2019年10月7日 16 | * @author Way Lau 17 | */ 18 | public class TimeServer { 19 | 20 | private int port; 21 | 22 | public TimeServer(int port) { 23 | this.port = port; 24 | } 25 | 26 | public void run() throws Exception { 27 | EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1) 28 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 29 | try { 30 | ServerBootstrap b = new ServerBootstrap(); // (2) 31 | b.group(bossGroup, workerGroup) 32 | .channel(NioServerSocketChannel.class) // (3) 33 | .childHandler(new ChannelInitializer() { // (4) 34 | @Override 35 | public void initChannel(SocketChannel ch) throws Exception { 36 | ch.pipeline().addLast(new TimeServerHandler()); 37 | } 38 | }) 39 | .option(ChannelOption.SO_BACKLOG, 128) // (5) 40 | .childOption(ChannelOption.SO_KEEPALIVE, true); // (6) 41 | 42 | // 绑定端口,开始接收进来的连接 43 | ChannelFuture f = b.bind(port).sync(); // (7) 44 | 45 | // 等待服务器 socket 关闭 。 46 | // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。 47 | f.channel().closeFuture().sync(); 48 | } finally { 49 | workerGroup.shutdownGracefully(); 50 | bossGroup.shutdownGracefully(); 51 | } 52 | } 53 | 54 | public static void main(String[] args) throws Exception { 55 | int port; 56 | if (args.length > 0) { 57 | port = Integer.parseInt(args[0]); 58 | } else { 59 | port = 8080; 60 | } 61 | new TimeServer(port).run(); 62 | } 63 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/time/TimeServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.time; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelFutureListener; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.ChannelInboundHandlerAdapter; 8 | 9 | /** 10 | * Time Server Handler. 11 | * 12 | * @since 1.0.0 2019年10月7日 13 | * @author Way Lau 14 | */ 15 | public class TimeServerHandler extends ChannelInboundHandlerAdapter { 16 | 17 | @Override 18 | public void channelActive(final ChannelHandlerContext ctx) { 19 | final ByteBuf time = ctx.alloc().buffer(4); 20 | time.writeInt((int) (System.currentTimeMillis() / 1000L + 2208988800L)); 21 | 22 | // 出站操作返回ChannelFuture 23 | final ChannelFuture f = ctx.writeAndFlush(time); 24 | 25 | // 增加监听器 26 | f.addListener(new ChannelFutureListener() { 27 | 28 | // 操作完成,关闭管道 29 | @Override 30 | public void operationComplete(ChannelFuture future) { 31 | ctx.close(); 32 | } 33 | }); 34 | } 35 | 36 | @Override 37 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 38 | cause.printStackTrace(); 39 | ctx.close(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/websocketchat/WebSocketChatServer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.websocketchat; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelOption; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.nio.NioEventLoopGroup; 8 | import io.netty.channel.socket.nio.NioServerSocketChannel; 9 | 10 | /** 11 | * WebSocket Chat Server. 12 | * 13 | * @since 1.0.0 2020年1月1日 14 | * @author Way Lau 15 | */ 16 | public class WebSocketChatServer { 17 | 18 | private int port; 19 | 20 | public WebSocketChatServer(int port) { 21 | this.port = port; 22 | } 23 | 24 | public void run() throws Exception { 25 | 26 | EventLoopGroup bossGroup = new NioEventLoopGroup(1); // (1) 27 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 28 | try { 29 | ServerBootstrap b = new ServerBootstrap(); // (2) 30 | b.group(bossGroup, workerGroup) 31 | .channel(NioServerSocketChannel.class) // (3) 32 | .childHandler(new WebSocketChatServerInitializer()) //(4) 33 | .option(ChannelOption.SO_BACKLOG, 128) // (5) 34 | .childOption(ChannelOption.SO_KEEPALIVE, true); // (6) 35 | 36 | System.out.println("WebsocketChatServer 启动了" + port); 37 | 38 | // 绑定端口,开始接收进来的连接 39 | ChannelFuture f = b.bind(port).sync(); // (7) 40 | 41 | // 等待服务器 socket 关闭 。 42 | // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。 43 | f.channel().closeFuture().sync(); 44 | 45 | } finally { 46 | workerGroup.shutdownGracefully(); 47 | bossGroup.shutdownGracefully(); 48 | 49 | System.out.println("WebsocketChatServer 关闭了"); 50 | } 51 | } 52 | 53 | public static void main(String[] args) throws Exception { 54 | int port; 55 | if (args.length > 0) { 56 | port = Integer.parseInt(args[0]); 57 | } else { 58 | port = 8080; 59 | } 60 | new WebSocketChatServer(port).run(); 61 | 62 | } 63 | } -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/demo/websocketchat/WebSocketChatServerInitializer.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.websocketchat; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.http.HttpObjectAggregator; 7 | import io.netty.handler.codec.http.HttpServerCodec; 8 | import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; 9 | import io.netty.handler.stream.ChunkedWriteHandler; 10 | 11 | /** 12 | * WebSocketChatServer ChannelInitializer. 13 | * 14 | * @since 1.0.0 2020年1月1日 15 | * @author Way Lau 16 | */ 17 | public class WebSocketChatServerInitializer extends 18 | ChannelInitializer { //(1) 19 | 20 | @Override 21 | public void initChannel(SocketChannel ch) throws Exception {//(2) 22 | ChannelPipeline pipeline = ch.pipeline(); 23 | 24 | pipeline.addLast(new HttpServerCodec()); 25 | pipeline.addLast(new HttpObjectAggregator(64*1024)); 26 | pipeline.addLast(new ChunkedWriteHandler()); 27 | pipeline.addLast(new HttpRequestHandler("/ws")); 28 | pipeline.addLast(new WebSocketServerProtocolHandler("/ws")); 29 | pipeline.addLast(new TextWebSocketFrameHandler()); 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/util/ByteObjConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.waylau.netty.util; 5 | 6 | import java.io.ByteArrayInputStream; 7 | import java.io.ByteArrayOutputStream; 8 | import java.io.IOException; 9 | import java.io.ObjectInputStream; 10 | import java.io.ObjectOutputStream; 11 | 12 | /** 13 | * 说明: 14 | * 15 | * @author waylau.com 2015年11月9日 16 | */ 17 | public class ByteObjConverter { 18 | 19 | public static Object ByteToObject(byte[] bytes) { 20 | Object obj = null; 21 | ByteArrayInputStream bi = new ByteArrayInputStream(bytes); 22 | ObjectInputStream oi = null; 23 | try { 24 | oi = new ObjectInputStream(bi); 25 | obj = oi.readObject(); 26 | } catch (Exception e) { 27 | e.printStackTrace(); 28 | } finally { 29 | try { 30 | bi.close(); 31 | } catch (IOException e) { 32 | e.printStackTrace(); 33 | } 34 | try { 35 | oi.close(); 36 | } catch (IOException e) { 37 | e.printStackTrace(); 38 | } 39 | } 40 | return obj; 41 | } 42 | 43 | public static byte[] ObjectToByte(Object obj) { 44 | byte[] bytes = null; 45 | ByteArrayOutputStream bo = new ByteArrayOutputStream(); 46 | ObjectOutputStream oo = null; 47 | try { 48 | oo = new ObjectOutputStream(bo); 49 | oo.writeObject(obj); 50 | bytes = bo.toByteArray(); 51 | } catch (Exception e) { 52 | e.printStackTrace(); 53 | } finally { 54 | try { 55 | bo.close(); 56 | } catch (IOException e) { 57 | e.printStackTrace(); 58 | } 59 | try { 60 | oo.close(); 61 | } catch (IOException e) { 62 | e.printStackTrace(); 63 | } 64 | } 65 | return (bytes); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /netty4-demos/src/main/java/com/waylau/netty/util/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | /** 5 | * 说明:工具包 6 | * 7 | * @author waylau.com 2015年11月10日 8 | */ 9 | package com.waylau.netty.util; -------------------------------------------------------------------------------- /netty4-demos/src/main/resources/WebsocketChatClient.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebSocket Chat 6 | 7 | 8 | 42 |
43 |

WebSocket 聊天室:

44 | 45 |
46 | 47 | 48 | 49 |
50 |
51 |
52 | 更多例子请访问 waylau.com 53 | 54 | -------------------------------------------------------------------------------- /netty4-demos/src/main/resources/ssl/nettyClient.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/netty-4-user-guide-demos/a31932a644de534dd1d7647bdf029bd45a85a403/netty4-demos/src/main/resources/ssl/nettyClient.cer -------------------------------------------------------------------------------- /netty4-demos/src/main/resources/ssl/nettyClient.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/netty-4-user-guide-demos/a31932a644de534dd1d7647bdf029bd45a85a403/netty4-demos/src/main/resources/ssl/nettyClient.jks -------------------------------------------------------------------------------- /netty4-demos/src/main/resources/ssl/nettyServer.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/netty-4-user-guide-demos/a31932a644de534dd1d7647bdf029bd45a85a403/netty4-demos/src/main/resources/ssl/nettyServer.cer -------------------------------------------------------------------------------- /netty4-demos/src/main/resources/ssl/nettyServer.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waylau/netty-4-user-guide-demos/a31932a644de534dd1d7647bdf029bd45a85a403/netty4-demos/src/main/resources/ssl/nettyServer.jks -------------------------------------------------------------------------------- /netty4-demos/src/test/java/com/waylau/netty/demo/decoder/FixedLengthFrameDecoderTest.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.decoder; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertFalse; 5 | import static org.junit.jupiter.api.Assertions.assertNull; 6 | import static org.junit.jupiter.api.Assertions.assertTrue; 7 | 8 | import org.junit.jupiter.api.Test; 9 | 10 | import io.netty.buffer.ByteBuf; 11 | import io.netty.buffer.Unpooled; 12 | import io.netty.channel.embedded.EmbeddedChannel; 13 | import io.netty.handler.codec.FixedLengthFrameDecoder; 14 | 15 | /** 16 | * FixedLengthFrameDecoder Test. 17 | * 18 | * @since 1.0.0 2020年1月4日 19 | * @author Way Lau 20 | */ 21 | class FixedLengthFrameDecoderTest { 22 | 23 | @Test 24 | void testFramesDecoded() { 25 | ByteBuf buf = Unpooled.buffer(); 26 | for (int i = 0; i < 9; i++) { 27 | buf.writeByte(i); 28 | } 29 | ByteBuf input = buf.duplicate(); 30 | EmbeddedChannel channel = new EmbeddedChannel(new FixedLengthFrameDecoder(3)); 31 | 32 | // 写字节 33 | assertTrue(channel.writeInbound(input.retain())); 34 | assertTrue(channel.finish()); 35 | 36 | // 读消息 37 | ByteBuf read = (ByteBuf) channel.readInbound(); 38 | assertEquals(buf.readSlice(3), read); 39 | read.release(); 40 | read = (ByteBuf) channel.readInbound(); 41 | assertEquals(buf.readSlice(3), read); 42 | read.release(); 43 | read = (ByteBuf) channel.readInbound(); 44 | assertEquals(buf.readSlice(3), read); 45 | read.release(); 46 | assertNull(channel.readInbound()); 47 | buf.release(); 48 | } 49 | 50 | @Test 51 | void testFramesDecoded2() { 52 | ByteBuf buf = Unpooled.buffer(); 53 | for (int i = 0; i < 9; i++) { 54 | buf.writeByte(i); 55 | } 56 | ByteBuf input = buf.duplicate(); 57 | EmbeddedChannel channel = new EmbeddedChannel(new FixedLengthFrameDecoder(3)); 58 | assertFalse(channel.writeInbound(input.readBytes(2))); 59 | assertTrue(channel.writeInbound(input.readBytes(7))); 60 | assertTrue(channel.finish()); 61 | ByteBuf read = (ByteBuf) channel.readInbound(); 62 | assertEquals(buf.readSlice(3), read); 63 | read.release(); 64 | read = (ByteBuf) channel.readInbound(); 65 | assertEquals(buf.readSlice(3), read); 66 | read.release(); 67 | read = (ByteBuf) channel.readInbound(); 68 | assertEquals(buf.readSlice(3), read); 69 | read.release(); 70 | assertNull(channel.readInbound()); 71 | buf.release(); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /netty4-demos/src/test/java/com/waylau/netty/demo/encoder/AbsIntegerEncoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to https://waylau.com 3 | */ 4 | package com.waylau.netty.demo.encoder; 5 | 6 | import java.util.List; 7 | 8 | import io.netty.buffer.ByteBuf; 9 | import io.netty.channel.ChannelHandlerContext; 10 | import io.netty.handler.codec.MessageToMessageEncoder; 11 | 12 | /** 13 | * Abs Integer Encoder. 14 | * 15 | * @since 1.0.0 2020年1月4日 16 | * @author Way Lau 17 | */ 18 | public class AbsIntegerEncoder extends MessageToMessageEncoder { 19 | @Override 20 | protected void encode(ChannelHandlerContext channelHandlerContext, 21 | ByteBuf in, List out) throws Exception { 22 | while (in.readableBytes() >= 4) { 23 | int value = Math.abs(in.readInt()); 24 | out.add(value); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /netty4-demos/src/test/java/com/waylau/netty/demo/encoder/AbsIntegerEncoderTest.java: -------------------------------------------------------------------------------- 1 | package com.waylau.netty.demo.encoder; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertNull; 5 | import static org.junit.jupiter.api.Assertions.assertTrue; 6 | 7 | import org.junit.jupiter.api.Test; 8 | 9 | import io.netty.buffer.ByteBuf; 10 | import io.netty.buffer.Unpooled; 11 | import io.netty.channel.embedded.EmbeddedChannel; 12 | 13 | /** 14 | * AbsIntegerEncoder Test. 15 | * 16 | * @since 1.0.0 2020年1月4日 17 | * @author Way Lau 18 | */ 19 | class AbsIntegerEncoderTest { 20 | 21 | @Test 22 | void testEncoded() { 23 | ByteBuf buf = Unpooled.buffer(); 24 | for (int i = 1; i < 10; i++) { 25 | buf.writeInt(i * -1); //(1) 26 | } 27 | 28 | EmbeddedChannel channel = 29 | new EmbeddedChannel(new AbsIntegerEncoder()); //(2) 30 | assertTrue(channel.writeOutbound(buf)); //(3) 31 | assertTrue(channel.finish()); //(4) 32 | 33 | // 读字节 34 | for (int i = 1; i < 10; i++) { 35 | assertEquals(Integer.valueOf(i+""), 36 | channel.readOutbound()); //(5) 37 | } 38 | assertNull(channel.readOutbound()); 39 | } 40 | } 41 | --------------------------------------------------------------------------------