目录
springboot 项目可设置启动服务时启动netty服务
引入netty包
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.25.Final</version>
<scope>compile</scope>
</dependency>
启动服务并监听端口
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.net.InetSocketAddress;
@Component
@Slf4j
public class NettyServer {
public static void main(String[] args){
String url = "127.0.0.1";
int port = 7000;
InetSocketAddress address =new InetSocketAddress(url,port);
new NettyServer().start(address);
}
public void start(InetSocketAddress address){
/**
* 两个独立的Reactor线程池
* 一个用于接收客户端的TCP连接
* 另一个用于处理I/O相关的读写操作,或者执行系统Task、定时任务Task等。
*/
EventLoopGroup bossGroup =new NioEventLoopGroup(1);
EventLoopGroup worksGroup =new NioEventLoopGroup();
try {
//一个对服务端做配置和启动的类
ServerBootstrap bootstrap =new ServerBootstrap()//类似构造器
.group(bossGroup,worksGroup)//组的概念
.channel(NioServerSocketChannel.class)//NIO类的SocketServer通道
.localAddress(address)//服务地址
.childHandler(new ServerChannelInitializer())//拦截器实例化
.option(ChannelOption.SO_BACKLOG,128) //父渠道日志配置
.childOption(ChannelOption.SO_KEEPALIVE,true);//子渠道配置
//绑定端口,开始接收进来的连接
ChannelFuture future =bootstrap.bind(address).sync();
log.info("服务已启动,端口为"+address.getPort());
future.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
bossGroup.shutdownGracefully();
worksGroup.shutdownGracefully();
}
}
}
配置拦截器
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
channel.pipeline().addLast("decoder",new StringDecoder(CharsetUtil.UTF_8));
channel.pipeline().addLast("encoder",new StringEncoder(CharsetUtil.UTF_8));
channel.pipeline().addLast(new ServerHandlers());
}
}
客户端加入、退出、发送消息处理程序
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
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 ServerHandlers extends ChannelInboundHandlerAdapter {
/**
* 创建一个静态组
*/
private static ChannelGroup channels =new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
@Override
public void handlerAdded(ChannelHandlerContext ctx){
//加入ChannelGroup
channels.add(ctx.channel());
log.info(ctx.channel().id()+"的设备加入群聊"+"Online:"+channels.size());
}
@Override
public void handlerRemoved(ChannelHandlerContext context){
log.info(context.channel().id()+"的设备退出群聊"+"Online:"+channels.size());
}
@Override
public void channelActive(ChannelHandlerContext ctx) {
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//打印消息然后群发
log.info(msg.toString());
for (Channel channel:channels){
log.info("群发消息,向channelid==="+channel.id().asShortText()+" 发送消息");
channel.writeAndFlush(msg.toString());
}
}
/**
* 设备异常关闭
* @param ctx
* @param cause
* @throws Exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause)throws Exception{
log.info(ctx.channel().id()+"的设备出错"+"Online:"+channels.size());
ctx.close();
}
}
springboot 项目可设置启动服务时启动netty服务
application中新增如下代码
@Override
public void run(String... args) throws Exception {
String url = serverSocketHost;
int port = nettyPort;
InetSocketAddress address = new InetSocketAddress(url, port);
new NettyServer().start(address);
}
模拟客户端测试
可找TCP相关的工具,例如:TCPUDPDbg,百度自行下载