实践
创建项目
使用了Springboot来创建.毕竟好多开箱即用的东东.用着很舒服.
创建界面必选一个框架:Lombok.
不写getter和setter方法真的爽很多
导入jar包
Netty是在B站学习的.而那个老师的jar 是 下载下来手动导入的.emmm.
4.1.2版本的jar
编写服务端程序
public static void main(String[] args) throws InterruptedException {
// 只处理连接请求
EventLoopGroup bossGroup = new NioEventLoopGroup();
// 只处理也客户端的业务处理
EventLoopGroup workerGroup = new NioEventLoopGroup();
// 他们俩个都是无限循环
// 服务器端启动的对象:可以配置参数
ServerBootstrap serverBootStarp = new ServerBootstrap();
// 使用链式编程设置
serverBootStarp.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
// 线程队列的连接个数
.option(ChannelOption.SO_BACKLOG,128)
// 设置保持活动连接状态
.childOption(ChannelOption.SO_KEEPALIVE,true)
// 给 WorkerGroup 设置 对应的处理器
// 在 socketChannel 设置到 WorkerGroup的 selector 上时,需要的处理器
// 可以自定义,也可以是Netty提供
.childHandler(new ChannelInitializer<SocketChannel>() {// 创建一个通道初始化对象
// 给pipeline 设置处理器
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline()
// 在管道的最后增加处理器
// 自己继承 ChannelInboundHadlerAdapter,重写了方法
.addLast(new NettyServerHandler());
}
});
// 绑定一个端口并同步,生成了一个ChannelFuture对象
// 启动服务器,绑定端口
ChannelFuture ch = serverBootStarp.bind(6668).sync();
// 对关闭通道进行监听
// 有了 关闭通道的消息或事件时,采取处理
// 关于到异步 模型
ch.channel().closeFuture().sync();
}
分析
之前说过,服务端分为俩部分,一部分为BossGroup,另一部分是WorkerGroup.
1. 都拥有自己的Handler:用于监测是否有数据到达
2. 有自己的线程池:规定了活动的线程数量等等一些信息
3. 有bootServerstarp:启动助手,设置一些信息:
4. 还有 sync() 方法,涉及到了 netty的异步模型
... ...
自定义Handler
Client
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
/**
* 当通道就绪,就会触发该方法
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("client" + ctx);
ChannelFuture channelFuture = ctx.writeAndFlush(Unpooled.copiedBuffer("hello server", Charset.forName("utf8")));
}
/**
* 当通道有读取事件时,会触发
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
}
/**
* 发生了异常怎么办
* @param ctx
* @param cause
* @throws Exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
}
}
Server
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
/**
* 读取实际数据,可以在这里读取客户端发送的消息
* @param ctx 上下文对象,含有 管道:pipeLine,通道,SocketChannel
* pipeline 可以包含很多 handler
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx,Object msg) throws Exception {
}
/**
* 数据读取完毕
*
*/
@Override
public void channelReadComplete(ChannelHandlerContext ctx){
}
/**
* 处理异常的方法
* TODO 发生了关闭管道的事件
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
}
}
编写客户端程序
public static void main(String[] args) throws InterruptedException {
EventLoopGroup eventExecutors = null;
try{
// 客户端只需要一个事件循环组
eventExecutors = new NioEventLoopGroup();
// 客户端启动助手
Bootstrap bootstrap = new Bootstrap();
// 设置相关的参数
// 设置相关的group,想关的线程组
bootstrap.group(eventExecutors)
// 设置客户端通道的实现类型|实现类
.channel(NioSocketChannel.class)
// 服务器发送的消息,需要自己编写
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
// 加入自己的处理其
socketChannel.pipeline().addLast(new NettyClientHandler());
}
});
System.out.println("客户端准备好了");
// sync() 涉及到netty的异步模型
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 6668).sync();
// 给关闭通道进行监听
// 非阻塞的
channelFuture.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
// 优雅关闭
eventExecutors.shutdownGracefully();
}
}