Netty
程序员文章站
2024-03-09 14:27:53
...
一、概述
二、netty整体设计
2.1单线程模型
2.2 线程池模型
2.3 netty模型
2.4异步模型
三、核心API
四、入门案例
首先编写四个类
- NettyClient 客户端
- NettyHandler 客户端处理器
- NettyServer 服务端
- NettyServerHandler 服务端业务处理器
NettyClient类:
/*
* Copyright (C), 2013-2019, 天津大海云科技有限公司
*/
package com.jikang.last;
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 yangjikang
* @date 2019/7/16 16:30
* @modified By yangjikang
*/
public class NettyClient {
public static void main(String[] args) throws InterruptedException {
//1.创建一个线程组
EventLoopGroup group = new NioEventLoopGroup();
//2.创建客户端启动助手,完成相关配置
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)//3.设置线程组
.channel(NioSocketChannel.class)//4.设置客户端通道的实现类
.handler(new ChannelInitializer<SocketChannel>() {//5.创建一个通道初始化对象
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(
new NettyHandler());//6.往pipeline链中添加自定义的处理器
}
});
System.out.println("======客户端准备就绪======");
//启动客户端去连接服务端 connect方法是异步的,sync方法是同步阻塞的
ChannelFuture sync = bootstrap.connect("127.0.0.1", 9999).sync();
//8.关闭连接,异步非阻塞
sync.channel().closeFuture().sync();
}
}
NettyClientHandler类:
/*
* Copyright (C), 2013-2019, 天津大海云科技有限公司
*/
package com.jikang.last;
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;
/**
* 客户端业务处理类
*
* @author yangjikang
* @date 2019/7/16 16:31
* @modified By yangjikang
*/
public class NettyHandler extends ChannelInboundHandlerAdapter{
//通道就绪事件
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("Client:"+ctx);
ctx.writeAndFlush(Unpooled.copiedBuffer("老板什么时候发工资?", CharsetUtil.UTF_8));
}
//读取数据事件
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("channelRead 老板回复了...");
ByteBuf byteBuf = (ByteBuf) msg;
System.out.println("服务端发来的消息:"+byteBuf.toString(CharsetUtil.UTF_8));
}
}
NettyServer类:
/*
* Copyright (C), 2013-2019, 天津大海云科技有限公司
*/
package com.jikang.last;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* @author yangjikang
* @date 2019/7/16 16:30
* @modified By yangjikang
*/
public class NettyServer {
public static void main(String[] args) throws InterruptedException {
//1.创建一个线程组,接收客户端连接
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
//2.创建一个线程组,处理客户端请求
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
//3.创建服务器启动助手来配置参数
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,workerGroup)//4.设置两个线程组
.channel(NioServerSocketChannel.class)//5.使用NioServerSocketChannel作为服务端通道的实现
.option(ChannelOption.SO_BACKLOG,125)//6.设置线程队列等待连接的个数
.childOption(ChannelOption.SO_KEEPALIVE,true)//7.保持活动连接状态
.childHandler(new ChannelInitializer<SocketChannel>() {//8.创建通道初始化对象
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {//9.在pipeline链上末尾添加我们自定义的处理器
socketChannel.pipeline().addLast(new NettyServerHandler());
}
});
System.out.println("=======服务器配置准备就绪========");
ChannelFuture cf = serverBootstrap.bind(9999).sync();//10.绑定端口 bind方法是异步的,sync方法是同步阻塞的
System.out.println("=======服务器开始启动===========");
//11.关闭通道
cf.channel().closeFuture().sync();//异步
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
NettyServerHandler类:
/*
* Copyright (C), 2013-2019, 天津大海云科技有限公司
*/
package com.jikang.last;
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;
/**
* 服务器端业务处理类
*
* @author yangjikang
* @date 2019/7/16 16:31
* @modified By yangjikang
*/
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
//读取数据事件
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("Server:" + ctx);
ByteBuf byteBuf = (ByteBuf) msg;
System.out.println("客户端发来的消息:"+byteBuf.toString(CharsetUtil.UTF_8));
}
//数据读取完毕事件
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.copiedBuffer("再等等吧,现在厂里效益不好!",CharsetUtil.UTF_8));
}
//异常发生事件
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
聊天案例:
- ChatClient 客户端
- ChatClientHandler 客户端处理器
- ChatServer 服务端
- ChatServerHandler 服务端业务处理器
ChatClient 类:
/*
* Copyright (C), 2013-2019, 天津大海云科技有限公司
*/
package com.jikang.chat;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import java.util.Scanner;
/**
* @author yangjikang
* @date 2019/7/17 9:57
* @modified By yangjikang
*/
public class ChatClient {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast("decoder",new StringDecoder());
pipeline.addLast("encoder",new StringEncoder());
pipeline.addLast(new ChatClientHandler());
}
});
ChannelFuture sync = bootstrap.connect("127.0.0.1", 9999).sync();
Channel channel = sync.channel();
System.out.println("========"+channel.localAddress().toString().substring(1)+"===========");
System.out.println("--------------聊天程序开启------------------");
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
String s = scanner.next();
channel.writeAndFlush(s+"\r\n");
}
group.shutdownGracefully();
}
}
ChatClientHandler类:
/*
* Copyright (C), 2013-2019, 天津大海云科技有限公司
*/
package com.jikang.chat;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
* @author yangjikang
* @date 2019/7/17 9:57
* @modified By yangjikang
*/
public class ChatClientHandler extends SimpleChannelInboundHandler<String>{
@Override
protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception {
System.out.println("[Client]:"+s.trim());
}
}
ChatServer类:
/*
* Copyright (C), 2013-2019, 天津大海云科技有限公司
*/
package com.jikang.chat;
import io.netty.bootstrap.Bootstrap;
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;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* @author yangjikang
* @date 2019/7/17 9:34
* @modified By yangjikang
*/
public class ChatServer {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = new ServerBootstrap();
System.out.println("----服务器开始配置----");
serverBootstrap.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,128)
.childOption(ChannelOption.SO_KEEPALIVE,true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast("decoder",new StringDecoder());//解码器
pipeline.addLast("encoder",new StringEncoder());//编码器
pipeline.addLast(new ChatServerHandler());//处理器
}
});
System.out.println("----服务器配置完成----");
System.out.println("----服务器开始启动----");
ChannelFuture cf = serverBootstrap.bind(9999).sync();
cf.channel().closeFuture().sync();
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
System.out.println("==============");
}
}
ChatServerHandler类:
/*
* Copyright (C), 2013-2019, 天津大海云科技有限公司
*/
package com.jikang.chat;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.util.ArrayList;
import java.util.List;
/**
* @author yangjikang
* @date 2019/7/17 9:35
* @modified By yangjikang
*/
public class ChatServerHandler extends SimpleChannelInboundHandler<String> {
private static List<Channel> channels = new ArrayList<>();
//读取数据
@Override
protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception {
Channel channel = ctx.channel();
String address = channel.remoteAddress().toString().substring(1);
for (Channel channel1 : channels) {
if (channel1 != channel) {
channel1.writeAndFlush(address + ":说->" + s+"\r\n");
}
}
}
//通道就绪
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
channels.add(channel);
System.out.println("----" + channel.remoteAddress().toString().substring(1) + ":上线------");
}
//通道未就绪
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
channels.remove(channel);
System.out.println("----" + channel.remoteAddress().toString().substring(1) + ":下线------");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("出现异常的原因--->"+cause.getMessage());
}
}
推荐阅读
-
Netty总结
-
Netty初识之DiscardServer
-
Netty4实战第六章:ChannelHandler
-
Netty
-
Java NIO框架Mina、Netty、Grizzly介绍与对比 博客分类: IO
-
java游戏架构那点事儿(二) 博客分类: java 游戏 游戏框架netty
-
使用 Netty 进行 UDP 网络编程 博客分类: java编程
-
基于netty的websocket开发小结 博客分类: java编程 javahtml5websocket
-
基于netty的websocket开发小结 博客分类: java编程 javahtml5websocket
-
基于netty4.0+spring的游戏完整架构 博客分类: java 游戏