简述:
Springboot项目的web服务后台,web服务运行在9100端口。
后台使用netty实现了TCP服务,运行在8000端口。
启动截图如下:
pom依赖
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.25.Final</version>
</dependency>
netty服务代码
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;
/**
* netty服务器,主要用于与客户端通讯
*/
public class NettyServer {
private final int port; //监听端口
public NettyServer(int port) {
this.port = port;
}
//编写run方法,处理客户端的请求
public void run() throws Exception {
//创建两个线程组
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(); //8个NioEventLoop
try {
ServerBootstrap b = new ServerBootstrap();
b.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 ch) throws Exception {
//获取到pipeline
ChannelPipeline pipeline = ch.pipeline();
//向pipeline加入解码器
pipeline.addLast("decoder", new StringDecoder());
//向pipeline加入编码器
pipeline.addLast("encoder", new StringEncoder());
//加入自己的业务处理handler
pipeline.addLast(new NettyServerHandler());
}
});
System.out.println("netty服务器启动成功(port:" + port + ")......");
ChannelFuture channelFuture = b.bind(port).sync();
//监听关闭
channelFuture.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
netty业务处理handler
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class NettyServerHandler extends SimpleChannelInboundHandler<String> {
//定义一个channle 组,管理所有的channel
//GlobalEventExecutor.INSTANCE) 是全局的事件执行器,是一个单例
public static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
/**
* 有客户端与服务器发生连接时执行此方法
* 1.打印提示信息
* 2.将客户端保存到 channelGroup 中
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
System.err.println("有新的客户端与服务器发生连接。客户端地址:" + channel.remoteAddress());
channelGroup.add(channel);
}
/**
* 当有客户端与服务器断开连接时执行此方法,此时会自动将此客户端从 channelGroup 中移除
* 1.打印提示信息
*/
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
System.err.println("有客户端与服务器断开连接。客户端地址:" + channel.remoteAddress());
}
/**
* 表示channel 处于活动状态
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println(ctx.channel().remoteAddress() + " 处于活动状态");
}
/**
* 表示channel 处于不活动状态
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println(ctx.channel().remoteAddress() + " 处于不活动状态");
}
/**
* 读取到客户端发来的数据数据
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
//获取到当前channel
Channel channel = ctx.channel();
System.err.println("有客户端发来的数据。地址:" + channel.remoteAddress() + " 内容:" + msg);
}
/**
* 处理异常
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
log.error("发生异常。异常信息:{}", cause.getMessage());
//关闭通道
ctx.close();
}
}
Springboot项目中启动netty服务
启动类修改:
测试结果截图
服务启动,及客户端连接
客户端给服务器发送数据
服务器给客户端发送数据
服务器查看当前所有连接的客户端
服务器获取到所有客户单的ip地址及端口号后,即可通过其给指定客户端发送数据