从零学Netty(七)Netty实现 多人聊天室
实例demo
编写服务端
/**
* 服务端
*
* @author LionLi
*/
public class GroupChatServer {
private final int port;
public GroupChatServer(int port) {
this.port = port;
}
public void run() throws Exception {
// boss组 使用一个线程接收和分发请求
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
// worker工作组 默认线程数8 处理实际请求
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
// 主线程处理类
.channel(NioServerSocketChannel.class)
// 针对主线程的配置 分配线程最大数量 128
.option(ChannelOption.SO_BACKLOG, 128)
// 针对子线程的配置 保持长连接
.childOption(ChannelOption.SO_KEEPALIVE, true)
// 子线程处理类
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
// 加入 编解码handler
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
// 加入自己的业务处理handler
pipeline.addLast(new GroupChatServerHandler());
}
});
System.out.println("服务器正在监听......");
ChannelFuture channelFuture = b.bind(port).sync();
// 监听关闭
channelFuture.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
new GroupChatServer(8088).run();
}
}
编写服务端业务处理器
/**
* 服务端业务处理器
*
* @author LionLi
*/
public class GroupChatServerHandler extends SimpleChannelInboundHandler<String> {
/**
* 定义一个channle 组,管理所有的channel
* GlobalEventExecutor.INSTANCE) 是全局的事件执行器,是一个单例
* 内部使用ConcurrentHashMap管理,线程安全
*/
private static final ChannelGroup CHANNEL_GROUP = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
/**
* 初始化连接事件
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) {
Channel channel = ctx.channel();
CHANNEL_GROUP.add(channel);
}
/**
* 连接断开事件
*/
@Override
public void handlerRemoved(ChannelHandlerContext ctx) {
System.out.println("聊天室人数:" + CHANNEL_GROUP.size());
}
/**
* 通道新增事件
*/
@Override
public void channelActive(ChannelHandlerContext ctx) {
System.out.println(ctx.channel().remoteAddress() + " 上线了");
}
/**
* 通道关闭事件
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) {
System.out.println(ctx.channel().remoteAddress() + " 离线了");
}
/**
* 读取数据
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
CHANNEL_GROUP.writeAndFlush(msg);
}
/**
* 异常事件
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
//关闭通道
ctx.close();
}
}
编写客户端
/**
* 客户端
*
* @author LionLi
*/
public class GroupChatClient {
private final String host;
private final int port;
private final String username;
public GroupChatClient(String host, int port, String username) {
this.host = host;
this.port = port;
this.username = username;
}
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap()
.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
//加入 编解码handler
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
//加入自定义的handler
pipeline.addLast(new GroupChatClientHandler());
}
});
ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
Channel channel = channelFuture.channel();
channel.writeAndFlush(username + " 上线了");
//客户端需要输入信息,创建一个扫描器
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
String msg = scanner.nextLine();
if ("exit".equals(msg)) {
channel.writeAndFlush(username + " 离开了");
break;
} else {
channel.writeAndFlush(username + ":" + msg);
}
}
} finally {
group.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
System.out.print("请输入用户名: ");
Scanner scanner = new Scanner(System.in);
String username = scanner.nextLine();
new GroupChatClient("localhost", 8088, username).run();
}
}
编写客户端业务处理器
/**
* 客户端业务处理器
*
* @author LionLi
*/
public class GroupChatClientHandler extends SimpleChannelInboundHandler<String> {
/**
* 读取数据
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
System.out.println(msg.trim());
}
}
测试
- 场景如下:
- 启动服务端
- 顺序启动客户端 群友ABC 并输入用户名
- 分别打招呼
- 倒序退出客户端 群友ABC
项目已上传到gitee
地址: netty-demo
如果帮到您了,请帮忙点个star
还没有评论,来说两句吧...