希望和你一起遇见更好的自己|

方家小白

园龄:8年11个月粉丝:7关注:8

Springboot集成Netty

添加依赖

<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.72.Final</version>
</dependency>

创建服务

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import java.net.InetSocketAddress;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* Netty 服务端
*
* @author fangjiaxiaobai
* @date 2022-01-07 23:37
*/
@Slf4j
@Component
public class RouterServer2 {
/**
* boss 线程组用于处理连接工作
*/
private final EventLoopGroup boss = new NioEventLoopGroup();
/**
* work 线程组用于数据处理
*/
private final EventLoopGroup work = new NioEventLoopGroup();
@Resource
private ChannelHandler childHandler;
/**
* SpringBoot 启动的时候 调用
*
* @throws InterruptedException 中断异常
*/
@PostConstruct
public void init() throws InterruptedException {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boss, work)
// 指定Channel
.channel(NioServerSocketChannel.class)
//使用指定的端口设置套接字地址
.localAddress(new InetSocketAddress(7788))
//服务端可连接队列数,对应TCP/IP协议listen函数中backlog参数
.option(ChannelOption.SO_BACKLOG, 1024)
//设置TCP长连接,一般如果两个小时内没有数据的通信时,TCP会自动发送一个活动探测数据报文
.childOption(ChannelOption.SO_KEEPALIVE, true)
//将小的数据包包装成更大的帧进行传送,提高网络的负载,即TCP延迟传输
.childOption(ChannelOption.TCP_NODELAY, true)
.childHandler(new ChannelInitializer<Channel>() { ④
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline()
//添加编码器 ⓪
.addLast(new RouterMessageEncode())
//添加Netty 自带的 换行解码器(用来解决 沾包,拆包) ①
.addLast(new LineBasedFrameDecoder(1024))
//添加自定义的 解码器 ②
.addLast(new RouterMessageDecode())
//添加 接收消息的 处理器 ③
.addLast(new ServiceMessageReceiveHandler());
}
});
ChannelFuture future = bootstrap.bind().sync();
if (future.isSuccess()) {
log.info("start router Server success on port 7788");
}
}
/**
* SpringBoot 销毁的时候 调用
*
* @throws InterruptedException 中断异常
*/
@PreDestroy
public void destory() throws InterruptedException {
boss.shutdownGracefully().sync();
work.shutdownGracefully().sync();
log.info("关闭Netty");
}
}

🔥 ⓪:RouterMessageEncode: 这个是我们自己实现的消息编码器。
🔥①: 使用Netty提供的包处理工具,处理粘包问题已经用来拆包。
🔥②: 自定义的解码器。
🔥③: 自定义的消息处理器。 通用用来编写业务逻辑。
🔥④: 这里配置的是在Netty 启动时,需要添加的 Channel.

自定义编码器

import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
/**
* 编码器
*
* @author fangjiaxiaobai
* @date 2022-01-07 23:50
*/
@Slf4j
public class RouterMessageEncode extends MessageToMessageEncoder<String> {
@Override
protected void encode(ChannelHandlerContext channelHandlerContext, String message,
List<Object> list) throws Exception {
list.add(ByteBufUtil.encodeString(channelHandlerContext.alloc(), CharBuffer.wrap(message), Charset.defaultCharset()));
}
}

自定义解码器

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import java.nio.charset.Charset;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
/**
* 解码器
*
* @author fangjiaxiaobai
* @date 2022-01-07 23:54
*/
@Slf4j
public class RouterMessageDecode extends MessageToMessageDecoder<ByteBuf> {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> list) throws Exception {
// todo 解码
String message = msg.toString(Charset.defaultCharset());
list.add(message);
}
}

消息处理逻辑

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
/**
* 消息处理器
*
* @author fangjiaxiaobai
* @date 2022-01-07 23:59
*/
@Slf4j
public class ServiceMessageReceiveHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("收到消息:" + msg);
}
/**
* 注册一个 channel
*
* @param ctx ChannelHandlerContext
* @throws Exception 异常
*/
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
super.channelRegistered(ctx);
log.info("channel registed ...");
}
/**
* channel 退出
*
* @param ctx
* @throws Exception
*/
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
super.channelUnregistered(ctx);
log.info("channel unregistered ....");
}
/**
* 接收到的事件
*
* @param ctx ChannelHandlerContext
* @param evt Object
* @throws Exception 异常
*/
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
super.userEventTriggered(ctx, evt);
if (evt instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent) evt;
System.out.println("event:" + event.state());
}
}
/**
* 通道异常 应该在此关闭通道
*
* @param ctx
* @param cause
* @throws Exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
}
}

测试

编写一个客户端进行测试

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.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringEncoder;
/**
* @author fangjiaxiaobai
* @date 2022-01-08 00:40
*/
public class RouteClient {
public static void main(String[] args) throws InterruptedException {
Bootstrap bootstrap = new Bootstrap();
EventLoopGroup group = new NioEventLoopGroup();
bootstrap.group(group);
// 第2步 绑定客户端通道
bootstrap.channel(NioSocketChannel.class);
//第3步 给NIoSocketChannel初始化handler, 处理读写事件
//通道是NioSocketChannel
bootstrap.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
//字符串编码器,一定要加在SimpleClientHandler 的上面
ch.pipeline().addLast(new StringEncoder())
.addLast(new DelimiterBasedFrameDecoder(
Integer.MAX_VALUE, Delimiters.lineDelimiter()[0]));
}
});
//连接服务器
ChannelFuture future = bootstrap.connect("localhost", 7788).sync();
System.out.println(future.isSuccess());
for (int i = 0; i < 10; i++) {
future.channel().writeAndFlush("test netty message\r\n").sync(); ⑤
}
System.out.println("发送成功。。。。。");
}
}

🔥⑤ 注意这里,需要加上 \r\n, 否则你永远收不到消息。

最后

期望与你一起遇见更好的自己

期望与你一起遇见更好的自己

扫码或搜索:方家小白
发送 RFUEDS
即可立即永久解锁本站全部文章

本文作者:方家小白

本文链接:https://www.cnblogs.com/wxy540843763/p/15776474.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   方家小白  阅读(489)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.