我其他文章有简单的介绍netty流程,这边就不叙述了,直接贴代码了:
(1)NettyServer——服务端:
public static void main(String[] args) throws InterruptedException {
NettyServerDemo.start();
}
public static void start() throws InterruptedException {
//其中一个是处理网络连接,另一个是线程组是处理客户端的链接
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();
//启动辅助类
ServerBootstrap serverBootstrap = new ServerBootstrap();
//设置两个线程组
serverBootstrap.group(bossGroup,workGroup)
//精华部分,设置通道的底层实现,通过NioServerSocketChannel,这也是Netty的与NIO搭配的地方(此处作为服务器端通道的实现)
.channel(NioServerSocketChannel.class)
//这套机制是在2个小时左右没有接到上层链接时激活
.option(ChannelOption.SO_KEEPALIVE,true)
//是否启用心跳保活机制。在双方TCP套接字建立连接后(即都进入ESTABLISHED状态)
.childOption(ChannelOption.SO_KEEPALIVE,true)
.childHandler(new ChannelInitializer<SocketChannel>() {
//创建一个通道初始化对象
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//此处添加规则,自定义的
socketChannel.pipeline().addLast(new ServerHandler());
}
});
ChannelFuture channelFuture = serverBootstrap.bind(8888).sync();
boolean active = channelFuture.channel().isActive();
if (active){
System.out.println("-----服务器启动成功-----");
}
}
(2)ServerHandler——规则类,自己定义的
package com.example.netty;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
/**
* @author by Dong.Ding
* @Classname ServerHandler
* @Description TODO 服务器中的业务处理类
* @Date 2021/9/2 17:40
*/
public class ServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("进入channelActive");
super.channelActive(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("进入channelInactive");
super.channelInactive(ctx);
}
/**
*读取传输来的数据
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf byteBuf = (ByteBuf) msg;
System.out.println("进入channelRead" + byteBuf.toString(CharsetUtil.UTF_8));
super.channelRead(ctx, msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("进入channelReadComplete");
super.channelReadComplete(ctx);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("进入exceptionCaught");
super.exceptionCaught(ctx, cause);
}
}
我在channelRead中打印了一下我发送的数据,我是通过调试助手模拟TCP客户端进行连接的,如下图:
至此服务端成功,这个channelRead就是通信成功之后用于读取数据的,另外一个打印的进入channelReadComplete
是当数据读取完毕时进行的操作
(1)NettyClient——客户端(跟上使用的调试助手是一样的,只不过你这边直接自己写的)
package com.example.netty.client;
import io.netty.bootstrap.Bootstrap;
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.NioSocketChannel;
/**
* @author by Dong.Ding
* @Classname NettyClient
* @Description TODO
* @Date 2021/9/3 17:46
*/
public class NettyClient {
//网络客户端
public static void main(String[] args) throws Exception{
//创建一个线程组(不像服务端需要有连接等待的线程池)
EventLoopGroup group = new NioEventLoopGroup();
//创建客户端的服务启动助手完成相应配置
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
//创建一个通道初始化对象
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new NettyClientHandler());//往pipeline中添加自定义的handler
}
});
System.out.println("...Client is Ready...");
//启动客户端去连接服务器端(通过启动助手)
ChannelFuture cf = b.connect("127.0.0.1", 9999).sync();
//关闭连接(异步非阻塞)
cf.channel().closeFuture().sync();
}
}
(2)NettyClientHandler——规则(跟服务端类似,都是要有规则,就是通信处理的一些业务都在这里但是提醒一下,有人说在这里面处理业务会影响效率,最好这边不要涉及到任何的库操作,通过缓存或者redis进行操作,在其他地方再操作
)
package com.example.netty.client;
import io.netty.bootstrap.Bootstrap;
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.NioSocketChannel;
/**
* @author by Dong.Ding
* @Classname NettyClient
* @Description TODO
* @Date 2021/9/3 17:46
*/
public class NettyClient {
//网络客户端
public static void main(String[] args) throws Exception{
//创建一个线程组(不像服务端需要有连接等待的线程池)
EventLoopGroup group = new NioEventLoopGroup();
//创建客户端的服务启动助手完成相应配置
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
//创建一个通道初始化对象
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//往pipeline中添加自定义的handler
socketChannel.pipeline().addLast(new NettyClientHandler());
}
});
System.out.println("...Client is Ready...");
//启动客户端去连接服务器端(通过启动助手)
ChannelFuture cf = b.connect("127.0.0.1", 8888).sync();
//关闭连接(异步非阻塞)
cf.channel().closeFuture().sync();
}
}
然后我们运行客户端,结果如下:
也算是完成了最简单的netty通信,很多时候就是业务处理逻辑比较麻烦和处理数据,多了解就会通透很多。