1.创建服务端
public class NettyServer {
private Logger logger = LoggerFactory.getLogger(this.getClass());
public boolean isRunning = false;
private EventLoopGroup bossGroup = null;
private EventLoopGroup workGroup = null;
private ServerBootstrap bootstrap = null;
public void start(InetSocketAddress socketAddress) {
logger.info("Netty服务端启动成功,当前线程名称:" + Thread.currentThread().getName());
bossGroup = new NioEventLoopGroup(5);
workGroup = new NioEventLoopGroup(200);
bootstrap = new ServerBootstrap()
.group(bossGroup, workGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ServerChannelInitializer())
.localAddress(socketAddress)
.option(ChannelOption.SO_BACKLOG, 1024)
.childOption(ChannelOption.SO_KEEPALIVE, true);
try {
ChannelFuture future = bootstrap.bind(socketAddress).sync();
logger.info("服务器启动开始监听端口: {}", socketAddress.getPort());
isRunning = true;
future.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
logger.info("服务端执行结束");
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
isRunning = false;
}
}
public void stop(){
if(bossGroup != null && !bossGroup.isShutdown()){
bossGroup.shutdownGracefully();
}
if(workGroup != null && !workGroup.isShutdown()){
workGroup.shutdownGracefully();
}
isRunning = false;
logger.info("关闭服务器");
}
}
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private final NettyServerCacheTemplate nettyServerCacheTemplate = SpringUtils.getBean(NettyServerCacheTemplate.class);
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
logger.info("客户端["+ ctx.channel().id().asLongText() +"]建立链接成功");
nettyServerCacheTemplate.saveChannel(ctx.channel());
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
String name = Thread.currentThread().getName();
logger.info("服务器收到消息: {}", msg.toString());
System.out.println("当前线程名称:" + name + ":当前channel的id:" + ctx.channel().id().asLongText());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
logger.info("发生异常");
nettyServerCacheTemplate.deleteChannel(ctx.channel());
ctx.close();
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
logger.info("链接已关闭" +ctx.channel().id().asLongText());
nettyServerCacheTemplate.deleteChannel(ctx.channel());
}
}
public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
socketChannel.pipeline().addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
socketChannel.pipeline().addLast(new NettyServerHandler());
}
}
@Component
public class NettyServerCacheTemplate {
public static Map<String,Channel> channelMap = new ConcurrentHashMap<>();
public void saveChannel(Channel channel){
channelMap.put(channel.id().asLongText(),channel);
}
public Object getChannel(String name){
return channelMap.get(name);
}
public void deleteChannel(Channel channel){
channelMap.remove(channel.id().asLongText());
}
public Integer getSize(){
return channelMap.size();
}
public List<String> getOnline() {
return new ArrayList<>(channelMap.keySet());
}
public static String sendMsg(String msg, Channel channel) {
try {
if(channel.isActive()){
channel.write(msg);
channel.flush();
return "success";
}else {
return "不在线";
}
}catch (Exception e){
e.printStackTrace();
return "error";
}
}
}
2.创建客户端
public class NettyClient {
private Logger logger = LoggerFactory.getLogger(this.getClass());
public void start() {
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap()
.group(group)
.option(ChannelOption.TCP_NODELAY, true)
.channel(NioSocketChannel.class)
.handler(new NettyClientInitializer());
try {
ChannelFuture future = bootstrap.connect("127.0.0.1", 8091).sync();
logger.info("客户端成功....");
future.channel().attr(AttributeKey.valueOf("key")).set("sssss");
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
group.shutdownGracefully();
}
}
}
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private final NettyClientCacheTemplate nettyClientCacheTemplate = SpringUtils.getBean(NettyClientCacheTemplate.class);
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
logger.info("客户端与服务端链接成功");
nettyClientCacheTemplate.saveChannel(ctx.channel());
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Object key = ctx.channel().attr(AttributeKey.valueOf("key")).get();
System.out.println("获取attr中的值:" + key);
logger.info("客户端收到消息: {}", msg.toString());
logger.info("当前channel的编号是" +ctx.channel().id().asLongText());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
nettyClientCacheTemplate.deleteChannel(ctx.channel());
cause.printStackTrace();
ctx.close();
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
nettyClientCacheTemplate.deleteChannel(ctx.channel());
}
}
public class NettyClientInitializer extends ChannelInitializer<SocketChannel> {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast("decoder", new StringDecoder());
socketChannel.pipeline().addLast("encoder", new StringEncoder());
socketChannel.pipeline().addLast(new NettyClientHandler());
}
}
@Component
public class NettyClientCacheTemplate {
public static Map<String, Channel> channelMap = new ConcurrentHashMap<>();
public void saveChannel(Channel channel){
channelMap.put(channel.id().asLongText(),channel);
}
public Object getChannel(String name){
return channelMap.get(name);
}
public void deleteChannel(Channel channel){
channelMap.remove(channel.id().asLongText());
}
public Integer getSize(){
return channelMap.size();
}
public List<String> getOnline() {
return new ArrayList<>(channelMap.keySet());
}
public static String sendMsg(String msg, Channel channel) {
try {
if(channel.isActive()){
channel.write(msg);
channel.flush();
return "success";
}else {
return "不在线";
}
}catch (Exception e){
e.printStackTrace();
return "error";
}
}
}
3.创建线程池
@Configuration
@EnableAsync
public class ThreadPoolTaskConfig {
private static final int corePoolSize = 5;
private static final int maxPoolSize = 30;
private static final int keepAliveTime = 30;
private static final int queueCapacity = 10000;
private static final String threadNamePrefix = "xianchengchi-";
@Bean("taskExecutor")
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveTime);
executor.setThreadNamePrefix(threadNamePrefix);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
4.用线程池启动server
@Component
public class NettyPoolServer {
@Resource
private ThreadPoolTaskConfig poolTaskExecutor;
private static NettyPoolServer single = null;
private NettyServer nettyServer;
@PostConstruct
public void init() {
single = this;
single.poolTaskExecutor = this.poolTaskExecutor;
}
public static NettyPoolServer getSingle(){
return single;
}
public void run(){
poolTaskExecutor.taskExecutor().execute(new Runnable() {
@Override
public void run() {
System.out.println("NettyPoolServer当前线程池:" + Thread.currentThread().getName());
nettyServer = new NettyServer();
nettyServer.start(new InetSocketAddress("127.0.0.1", 8091));
}
});
}
public void stop(){
if(nettyServer!= null && nettyServer.isRunning){
nettyServer.stop();
}
}
public boolean getIsRunning(){
if(nettyServer == null){return false;}
return nettyServer.isRunning;
}
}
5.spring boot 启动
public static void main(String[] args) {
SpringApplication.run(BootAdminApplication.class, args);
NettyPoolServer.getSingle().run();
for (int i = 0 ; i< 20 ; i++){
new Thread(){
@Override
public void run() {
new NettyClient().start();
}
}.start();
}
}
6.客户端服务端调用测试
@RestController
@RequestMapping("nettyClient")
public class NettyClientController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Resource
private NettyClientCacheTemplate nettyClientCacheTemplate;
@GetMapping("/size")
public ResultModel getSize(){
return ResultModel.RESULT(ErrorMsg.SELECT_SUCCESS,nettyClientCacheTemplate.getSize());
}
@GetMapping("/online")
public ResultModel getOnline(){
List<String> returne = nettyClientCacheTemplate.getOnline();
return new ResultModel(ErrorMsg.SELECT_SUCCESS,returne);
}
@PostMapping("/send")
public ResultModel send(String name,String msg){
Channel channel = (Channel) nettyClientCacheTemplate.getChannel(name);
String result = nettyClientCacheTemplate.sendMsg(msg,channel);
return ResultModel.RESULT(ErrorMsg.SAVE_SUCCESS,"客户端发送成功" + result);
}
}
@RestController
@RequestMapping("nettyServer")
public class NettyServerController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Resource
private NettyServerCacheTemplate nettyCacheTemplate;
@GetMapping("/size")
public ResultModel getSize(){
return ResultModel.RESULT(ErrorMsg.SELECT_SUCCESS,nettyCacheTemplate.getSize());
}
@GetMapping("/online")
public ResultModel getOnline(){
List<String> returne = nettyCacheTemplate.getOnline();
return new ResultModel(ErrorMsg.SELECT_SUCCESS,returne);
}
@PostMapping("/send")
public ResultModel send(String name,String msg){
Channel channel = (Channel) nettyCacheTemplate.getChannel(name);
System.out.println(channel.isActive());
String result = nettyCacheTemplate.sendMsg(msg,channel);
return ResultModel.RESULT(ErrorMsg.SAVE_SUCCESS,"发送成功" + result);
}
}
7.其他
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.36.Final</version>
</dependency>
// 获取nameId
http://localhost:8090/nettyServer/online
// 发送
http://localhost:8090/nettyServer/send
客户端同样操作