Netty開發 —— 首個demo學習
阿新 • • 發佈:2020-07-30
1. 編寫服務端程式碼
編寫業務邏輯:讀取到客戶端的訊息時候,列印客戶端訊息,並給客戶端回覆一條訊息
import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; public class DemoNettyServer { public void bind(int port) throws Exception { // 主執行緒組 EventLoopGroup bossGroup = new NioEventLoopGroup(); // 從執行緒組 EventLoopGroup workerGroup = new NioEventLoopGroup(); try { // netty伺服器啟動類 ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workerGroup) //繫結兩個執行緒組 // 用於構造socketchannel工廠 .channel(NioServerSocketChannel.class) //指定NIO的模式 .childHandler(new ChannelInitializer<SocketChannel>() { // 子處理器,用於處理workerGroup protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(new DemoNettyServerHandler()); } }); // 啟動server,繫結埠 ChannelFuture channelFuture = serverBootstrap.bind(8088).sync(); System.out.println("server start"); // 監聽關閉的channel,等待伺服器 socket 關閉 。設定位同步方式 channelFuture.channel().closeFuture().sync(); System.out.println("server close"); } finally { //退出執行緒組 bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { int port = 8080; new DemoNettyServer().bind(port); } }
import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; public class DemoNettyServerHandler extends ChannelInboundHandlerAdapter { /** * 本方法用於讀取客戶端傳送的資訊 */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("收到來自客服端的一條訊息"); ByteBuf result = (ByteBuf) msg; byte[] bytesMsg = new byte[result.readableBytes()]; // msg中儲存的是ByteBuf型別的資料,把資料讀取到byte[]中 result.readBytes(bytesMsg); String resultStr = new String(bytesMsg); // 接收並列印客戶端的資訊 System.out.println("客服端內容:" + resultStr); // 釋放資源,這行很關鍵 result.release(); // 向客戶端傳送訊息 String response = "我是server,我已經收到你的訊息: " + resultStr; // 在當前場景下,傳送的資料必須轉換成ByteBuf陣列 ByteBuf encoded = ctx.alloc().buffer(4 * response.length()); encoded.writeBytes(response.getBytes()); ctx.write(encoded); ctx.flush(); } /** * 本方法用作處理異常 */ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { // 當出現異常就關閉連線 cause.printStackTrace(); ctx.close(); } /** * 資訊獲取完畢後操作 */ @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } }
2. 編寫客戶端程式碼
編寫業務邏輯:獲取使用者輸入,連線服務端,傳送訊息,讀取服務端訊息,關閉連線。
import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import java.util.Scanner; public class DemoNettyClient { public void connect(String host, int port) throws Exception { EventLoopGroup worker = new NioEventLoopGroup(); try { // 客戶端啟動類程式 Bootstrap bootstrap = new Bootstrap(); /** *EventLoop的組 */ bootstrap.group(worker); /** * 用於構造socketchannel工廠 */ bootstrap.channel(NioSocketChannel.class); /**設定選項 * 引數:Socket的標準引數(key,value),可自行百度 保持呼吸,不要斷氣! * */ bootstrap.option(ChannelOption.SO_KEEPALIVE, true); /** * 自定義客戶端Handle(客戶端在這裡搞事情) */ bootstrap.handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addFirst(new DemoNettyClientHandler()); } }); /** 開啟客戶端監聽,連線到遠端節點,阻塞等待直到連線完成*/ ChannelFuture channelFuture = bootstrap.connect(host, port).sync(); /**阻塞等待資料,直到channel關閉(客戶端關閉)*/ channelFuture.channel().closeFuture().sync(); } finally { worker.shutdownGracefully(); } } public static void main(String[] args) throws Exception { while (true){ Scanner content = new Scanner(System.in); System.out.print("請輸入您要傳送的內容: "); Meesage.CLIENT_MESSAGE = content.nextLine(); DemoNettyClient client = new DemoNettyClient(); client.connect("127.0.0.1", 8088); } } }
import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; public class DemoNettyClientHandler extends ChannelInboundHandlerAdapter { /** * 服務端發過來訊息時呼叫 */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("收到來自服務端的一條訊息"); ByteBuf result = (ByteBuf) msg; byte[] result1 = new byte[result.readableBytes()]; result.readBytes(result1); System.out.println(new String(result1)); result.release(); //關閉連線 ctx.close(); } /** * 異常時呼叫 */ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } /** * 連線到伺服器呼叫 */ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { String msg = Meesage.CLIENT_MESSAGE; ByteBuf encoded = ctx.alloc().buffer(4 * msg.length()); encoded.writeBytes(msg.getBytes()); ctx.write(encoded); ctx.flush(); } }
public class Meesage { public static String CLIENT_MESSAGE = ""; public static String SERVER_MESSAGE = ""; }
3. 結果分析