1.首先创建NettyServer的主类
创建一个EventLoopGroup BossGroup用于处理连接,一个工作组 管理任务
package com.ccw.qhj.netty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* @version 1.0
* @projectName:com.ccw.qhj.netty
* @packageName:pratice
* @className:NettyServer
* @Description:[一句话描述该类的功能]
* @Author:qhj
* @CreateDate:2021/4/25 17:15
* @blog:[方法具体上行/下行参数文档]
*/
public class NettyServer {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup,workGroup) //设置俩个线程租,boss 线程组只做 连接处理,work做业务处理
.channel(NioServerSocketChannel.class) //使用 NioServerSocket 作为服务器通道实现
.childOption(ChannelOption.SO_BACKLOG,128) //设置线程队列得到得连接个数
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new NettyServerHandller());
}
});
ChannelFuture cf = bootstrap.bind(6666).sync();
cf.channel().closeFuture().sync();
}
}
2、创建一个自定义Handller处理 客户端操作
package com.ccw.qhj.netty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
/**
* @version 1.0
* @projectName:com.ccw.qhj.netty
* @packageName:pratice
* @className:NettyServerHandller
* @Description:[一句话描述该类的功能]
* @Author:qhj
* @CreateDate:2021/4/25 17:15
* @blog:[方法具体上行/下行参数文档]
*/
public class NettyServerHandller extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf byteBuf = (ByteBuf) msg;
System.out.println("server ctx = "+ctx);
System.out.println("客户端发送得信息是:"+byteBuf.toString(CharsetUtil.UTF_8));
System.out.println("客户端地址:"+ctx.channel().remoteAddress());
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.copiedBuffer("hello:客户端", CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.channel().close();
}
}
3、创建一个服务端的主类
只需要创建一个连接的工作组,管理连接即可
package com.ccw.qhj.netty;
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;
/**
* @version 1.0
* @projectName:com.ccw.qhj.netty
* @packageName:pratice
* @className:NettyClient
* @Description:[一句话描述该类的功能]
* @Author:qhj
* @CreateDate:2021/4/25 17:15
* @blog:[方法具体上行/下行参数文档]
*/
public class NettyClient {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup eventExecutors = new NioEventLoopGroup();
try { Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventExecutors)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new NettyClientHandller());
}
});
System.out.println("客户端OK!");
ChannelFuture cf = bootstrap.connect("127.0.0.1", 6666).sync();
cf.channel().closeFuture().sync();
}finally {
eventExecutors.shutdownGracefully();
}
}
}
4、创建客户端自定义handller 处理事件
package com.ccw.qhj.netty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
/**
* @version 1.0
* @projectName:com.ccw.qhj.netty
* @packageName:pratice
* @className:NettyClientHandller
* @Description:[一句话描述该类的功能]
* @Author:qhj
* @CreateDate:2021/4/25 17:16
* @blog:[方法具体上行/下行参数文档]
*/
public class NettyClientHandller extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("客户端+"+ctx);
ctx.writeAndFlush(Unpooled.copiedBuffer("hello:server,this client", CharsetUtil.UTF_8));
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf byteBuf = (ByteBuf) msg;
System.out.println("服务器端发送:"+byteBuf.toString(CharsetUtil.UTF_8));
System.out.println("服务端地址:"+ctx.channel().remoteAddress());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
}
}
5、基本思路
- 读写逻辑处理均是启动阶段通过给逻辑处理链Pipeline添加逻辑处理器实现连接数据的读写逻辑。
- 客户端连接成功回调逻辑处理器的channelActive()方法
- 客户端和服务端接收到对方的数据回调用各自逻辑处理器的channelRead()方法。
- 客户端和服务端向对方写数据调用writeAndFlush()方法
- 客户端和服务端交互的二进制数据传输载体为ByteBuf