1、添加依赖
<!--netty-->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.24.Final</version>
<scope>compile</scope>
</dependency>
2、创建TcpServer
@Slf4j
@Component
@Order(value = 1)
public class TcpServer implements CommandLineRunner {
@Value("${netty.ip}")
private String ip;
@Value("${netty.port}")
private int tcpPort;
@Autowired
private ProduceOrderService produceOrderService;
@Autowired
private TestRecordTopService testRecordTopService;
@Autowired
private TestRecordAllService testRecordAllService;
@Autowired
private ProduceOrderLogService produceOrderLogService;
@Async
@Override
public void run(String... args) {
start(ip, tcpPort);
}
public void start(String ip, int port) {
// master reactor
EventLoopGroup bossGroup = new NioEventLoopGroup();
// sub reactor
EventLoopGroup workGroup = new NioEventLoopGroup();
ChannelFuture f;
try {
// start
ServerBootstrap bootstrap = new ServerBootstrap();
// install NioEventLoopGroup
bootstrap.group(bossGroup, workGroup)
// set channel type NIO
.channel(NioServerSocketChannel.class)
// set connect params
.option(ChannelOption.SO_BACKLOG, 1024)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childOption(ChannelOption.TCP_NODELAY, true)
// set in/out event handler
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) {
// 添加分隔符解码器
ch.pipeline().addFirst(new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, Unpooled.copiedBuffer("&&".getBytes())));
ch.pipeline().addLast(new TcpMsgOutHandler());
ch.pipeline().addLast(new TcpActiveHandler());
ch.pipeline().addLast(new TcpMsgInHandler(produceOrderService, testRecordTopService, testRecordAllService, produceOrderLogService));
}
});
// bind port
f = bootstrap.bind(ip, port).sync();
if (f.isSuccess()) {
log.info("start tcp server success: {}", port);
} else {
log.warn("start tcp server failed: {}", f.cause().getMessage());
}
f.channel().closeFuture().sync();
} catch (Exception e) {
log.error("start tcp server error: {}", e.getMessage());
} finally {
workGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
3、Handler
@Slf4j
@ChannelHandler.Sharable
public class TcpActiveHandler extends ChannelInboundHandlerAdapter {
private final static AtomicLong activeCount = new AtomicLong(0);
@Override
public void channelActive(ChannelHandlerContext ctx) {
log.info("active client count: {}", activeCount.addAndGet(1));
}
@Override
public void channelInactive(ChannelHandlerContext ctx) {
log.info("active client count: {}", activeCount.decrementAndGet());
}
}
public class TcpMsgOutHandler extends ChannelOutboundHandlerAdapter {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
ctx.writeAndFlush(Unpooled.copiedBuffer(((String) msg).getBytes(StandardCharsets.UTF_8)));
}
}
@Slf4j
public class TcpMsgInHandler extends ChannelInboundHandlerAdapter {
private final ProduceOrderService produceOrderService;
private final TestRecordTopService testRecordTopService;
private final TestRecordAllService testRecordAllService;
private final ProduceOrderLogService produceOrderLogService;
public TcpMsgInHandler(ProduceOrderService produceOrderService, TestRecordTopService testRecordTopService,
TestRecordAllService testRecordAllService,ProduceOrderLogService produceOrderLogService) {
this.produceOrderService = produceOrderService;
this.testRecordTopService = testRecordTopService;
this.testRecordAllService = testRecordAllService;
this.produceOrderLogService = produceOrderLogService;
}
@Override
public void channelActive(ChannelHandlerContext ctx) {
log.info("client active: {}", ctx.channel().remoteAddress());
}
@Override
public void channelInactive(ChannelHandlerContext ctx) {
log.info("client inactive: {}", ctx.channel().remoteAddress());
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf byteBuf = (ByteBuf) msg;
String readMsg = byteBuf.toString(CharsetUtil.UTF_8);
ProduceMsg produceMsg = null;
try {
produceMsg = JSONObject.parseObject(readMsg, ProduceMsg.class);
} catch (Exception e) {
log.error("ProduceMsg 格式化消息失败!{}", e.getMessage());
ctx.write(ERROR_FORMAT_MSG);
}
if (produceMsg != null) {
log.info("Client Msg: {}", produceMsg);
TestRecordTopVO testRecordTopVO;
String msgType = produceMsg.getMsgType();
String msgContent = produceMsg.getMsgContent();
switch (msgType) {
// 通过IMEI号获取订单信息
case FIND_PRODUCE_ORDER_INFO:
ProduceOrderVO produceOrderVO = produceOrderService.queryProduceOrder(msgContent);
if (produceOrderVO == null) {
ctx.write(ERROR_RECORD_NOT_EXIST);
} else {
ctx.write(JSONObject.toJSONString(produceOrderVO));
}
break;
case SAVE_PRODUCE_DATA:
break;
case SAVE_PRODUCE_LOG:
break;
case PRODUCT_OUTBOUND:
break;
case GET_METER_CODE:
break;
case FIND_PRODUCE_RECORD_BY_IMEI:
break;
case FIND_PRODUCE_RECORD_BY_METER_CODE:
break;
default:
log.error("消息不存在!");
}
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
log.error("client {} exception: {}", ctx.channel().remoteAddress(), cause);
}
}