Netty4.0学习笔记系列之一:Server与Client的通讯

本文是学习Netty的第一篇文章,主要对Netty的Server和Client间的通讯机制进行验证。

Server与Client建立连接后,会执行以下的步骤:

1、Client向Server发送消息:Are you ok?

2、Server接收客户端发送的消息,并打印出来。

3、Server端向客户端发送消息:I am ok!

4、Client接收Server端发送的消息,并打印出来,通讯结束。

涉及到的类有4个:

1、HelloServer :server类,启动Netty server

2、HelloServerInHandler:server的handler,接收客户端消息,并向客户端发送消息

3、HelloClient:client类,建立于Netty server的连接

4、HelloClientIntHandler:client的handler,接收server端的消息,并向服务端发送消息

1、HelloServer代码如下:

1package com.guowl.testserver; 2 3import io.netty.bootstrap.ServerBootstrap; 4import io.netty.channel.ChannelFuture; 5import io.netty.channel.ChannelInitializer; 6import io.netty.channel.ChannelOption; 7import io.netty.channel.EventLoopGroup; 8import io.netty.channel.nio.NioEventLoopGroup; 9import io.netty.channel.socket.SocketChannel; 10import io.netty.channel.socket.nio.NioServerSocketChannel; 11 12public class HelloServer { 13 public void start(int port) throws Exception { 14 EventLoopGroup bossGroup = new NioEventLoopGroup(); 15 EventLoopGroup workerGroup = new NioEventLoopGroup(); 16 try { 17 ServerBootstrap b = new ServerBootstrap(); 18 b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) 19 .childHandler(new ChannelInitializer<SocketChannel>() { 20 @Override 21 public void initChannel(SocketChannel ch) 22 throws Exception { 23 // 注册handler 24 ch.pipeline().addLast(new HelloServerInHandler()); 25 } 26 }).option(ChannelOption.SO_BACKLOG, 128) 27 .childOption(ChannelOption.SO_KEEPALIVE, true); 28 29 ChannelFuture f = b.bind(port).sync(); 30 31 f.channel().closeFuture().sync(); 32 } finally { 33 workerGroup.shutdownGracefully(); 34 bossGroup.shutdownGracefully(); 35 } 36 } 37 38 public static void main(String[] args) throws Exception { 39 HelloServer server = new HelloServer(); 40 server.start(8000); 41 } 42}

2、HelloServerInHandler代码如下:

1package com.guowl.testserver; 2 3import io.netty.buffer.ByteBuf; 4import io.netty.channel.ChannelHandlerContext; 5import io.netty.channel.ChannelInboundHandlerAdapter; 6 7import org.slf4j.Logger; 8import org.slf4j.LoggerFactory; 9 10// 该handler是InboundHandler类型 11public class HelloServerInHandler extends ChannelInboundHandlerAdapter { 12 private static Logger logger = LoggerFactory 13 .getLogger(HelloServerInHandler.class); 14 15 @Override 16 public void channelRead(ChannelHandlerContext ctx, Object msg) 17 throws Exception { 18 logger.info("HelloServerInHandler.channelRead"); 19 ByteBuf result = (ByteBuf) msg; 20 byte[] result1 = new byte[result.readableBytes()]; 21 // msg中存储的是ByteBuf类型的数据,把数据读取到byte[]中 22 result.readBytes(result1); 23 String resultStr = new String(result1); 24 // 接收并打印客户端的信息 25 System.out.println("Client said:" + resultStr); 26 // 释放资源,这行很关键 27 result.release(); 28 29 // 向客户端发送消息 30 String response = "I am ok!"; 31 // 在当前场景下,发送的数据必须转换成ByteBuf数组 32 ByteBuf encoded = ctx.alloc().buffer(4 * response.length()); 33 encoded.writeBytes(response.getBytes()); 34 ctx.write(encoded); 35 ctx.flush(); 36 } 37 38 @Override 39 public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { 40 ctx.flush(); 41 } 42}

3、HelloClient代码如下:

1package com.guowl.testserver; 2 3import io.netty.bootstrap.Bootstrap; 4import io.netty.channel.ChannelFuture; 5import io.netty.channel.ChannelInitializer; 6import io.netty.channel.ChannelOption; 7import io.netty.channel.EventLoopGroup; 8import io.netty.channel.nio.NioEventLoopGroup; 9import io.netty.channel.socket.SocketChannel; 10import io.netty.channel.socket.nio.NioSocketChannel; 11 12public class HelloClient { 13 public void connect(String host, int port) throws Exception { 14 EventLoopGroup workerGroup = new NioEventLoopGroup(); 15 16 try { 17 Bootstrap b = new Bootstrap(); 18 b.group(workerGroup); 19 b.channel(NioSocketChannel.class); 20 b.option(ChannelOption.SO_KEEPALIVE, true); 21 b.handler(new ChannelInitializer<SocketChannel>() { 22 @Override 23 public void initChannel(SocketChannel ch) throws Exception { 24 ch.pipeline().addLast(new HelloClientIntHandler()); 25 } 26 }); 27 28 // Start the client. 29 ChannelFuture f = b.connect(host, port).sync(); 30 31 // Wait until the connection is closed. 32 f.channel().closeFuture().sync(); 33 } finally { 34 workerGroup.shutdownGracefully(); 35 } 36 37 } 38 39 public static void main(String[] args) throws Exception { 40 HelloClient client = new HelloClient(); 41 client.connect("127.0.0.1", 8000); 42 } 43}

4、HelloClientIntHandler代码如下:

1package com.guowl.testserver; 2 3import io.netty.buffer.ByteBuf; 4import io.netty.channel.ChannelHandlerContext; 5import io.netty.channel.ChannelInboundHandlerAdapter; 6 7import org.slf4j.Logger; 8import org.slf4j.LoggerFactory; 9 10public class HelloClientIntHandler extends ChannelInboundHandlerAdapter { 11 private static Logger logger = LoggerFactory.getLogger(HelloClientIntHandler.class); 12 13 // 接收server端的消息,并打印出来 14 @Override 15 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 16 logger.info("HelloClientIntHandler.channelRead"); 17 ByteBuf result = (ByteBuf) msg; 18 byte[] result1 = new byte[result.readableBytes()]; 19 result.readBytes(result1); 20 System.out.println("Server said:" + new String(result1)); 21 result.release(); 22 } 23 24 // 连接成功后,向server发送消息 25 @Override 26 public void channelActive(ChannelHandlerContext ctx) throws Exception { 27 logger.info("HelloClientIntHandler.channelActive"); 28 String msg = "Are you ok?"; 29 ByteBuf encoded = ctx.alloc().buffer(4 * msg.length()); 30 encoded.writeBytes(msg.getBytes()); 31 ctx.write(encoded); 32 ctx.flush(); 33 } 34}

通过上面简单的实例可以发现:

1、在没有任何encoder、decoder的情况下,Netty发送接收数据都是按照ByteBuf的形式,其它形式都是不合法的。

2、接收发送数据操作都是通过handler实现的,handler在netty中占据了非常重要的位置。

3、netty的handler是基于事件触发的,例如当client连接server成功后,client中的HelloClientIntHandler的channelActive方法会自动调用。

版权声明:本文为博主原创文章,未经博主允许不得转载。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

springcloud eureka.instance

1.在springcloud中服务的 InstanceID默认值是:${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance\_id:${server.port}},也就是:主机名:应用名:应用端口。如图1

GRPC的metadata使用

文章目录一、简析1、创建metadata2、发送metadata3、接收metadata二、代码举例1、proto文件编写2、server端编写3、client端编写三、实际使用举例四、参考文件在http请求当中我们可以设置head

Eureka Server集群重启问题追踪

问题在生产环境重启EurekaServer集群的时候,发现订单客户端调用分布式Id生成服务出错,1Caused by: com.netflix.client.ClientException: Load balancer does not have available server for client: IDG显示订单服务调不到

Spring Boot Admin配置详解

Client端配置参数默认值说明spring.boot.admin.client.enabledtrue是否启用springbootAdmin客户端spring.boot.admin.client.url要注册的server端的url地址。如果要同时在多个server端口注册,则用逗号分隔各个server端的url地址