Netty 多人聊天群
话不多说直接亮代码
hhhh
服务端代码
package com.example.demo.netty.chart;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
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;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class NettyChartServer {
private final int port;
final ChannelGroup clientGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
public NettyChartServer(int port) throws InterruptedException {
this.port = port;
}
{
run();
}
public void run() throws InterruptedException {
EventLoopGroup boosGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(boosGroup, workGroup);
serverBootstrap
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new ChannelInitHandler(clientGroup));
ChannelFuture sync = serverBootstrap.bind(port == 0 ? 6666 : port).sync();
log.info("服务器正常启动");
sync.channel().closeFuture().sync();
} finally {
boosGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
static class ChannelInitHandler extends ChannelInitializer<SocketChannel> {
private final ChannelGroup clientGroup;
public ChannelInitHandler(ChannelGroup clientGroup) {
this.clientGroup = clientGroup;
}
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast("custom", new ServerCustomHandler(clientGroup));
}
}
@Slf4j
static class ServerCustomHandler extends SimpleChannelInboundHandler<String> {
private final ChannelGroup clientGroup;
public ServerCustomHandler(ChannelGroup clientGroup) {
this.clientGroup = clientGroup;
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
clientGroup.add(channel);
log.info("客户端链接服务端 => {}", ctx.channel().remoteAddress());
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
clientGroup.remove(ctx.channel());
log.info("客户端断开链接 => {}", ctx.channel().remoteAddress());
}
/**
* 发生异常
*
* @param ctx 上下文信息
* @param cause 异常信息
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
log.error("发生异常 => {}", cause.getMessage());
}
/**
* 客户端上线
*
* @param ctx 上下文信息
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
String content = String.format("客户 => %s 上线", ctx.channel().remoteAddress());
log.info("{},当前在新人数 => {}", content, clientGroup.size());
clientGroup.writeAndFlush(content);
}
/**
* 客户端下线
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
String content = String.format("客户 => %s 下线", ctx.channel().remoteAddress());
log.info("{},当前在新人数 => {}", content, clientGroup.size());
clientGroup.writeAndFlush(Unpooled.copiedBuffer(content, CharsetUtil.UTF_8));
}
/**
* 获取到消息
*
* @param ctx the {@link ChannelHandlerContext} which this {@link SimpleChannelInboundHandler}
* belongs to
* @param msg the message to handle
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
String content = String.format("接收到 %s 的消息 => %s", ctx.channel().remoteAddress(), msg);
log.info(content);
clientGroup.writeAndFlush(Unpooled.copiedBuffer(content, CharsetUtil.UTF_8));
}
}
}
客户端代码
package com.example.demo.netty.chart;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;
import java.util.Scanner;
@Slf4j
public class NettyChartClient {
private final String host;
private final int port;
public NettyChartClient(String host, int port) throws InterruptedException {
this.host = host;
this.port = port;
}
{
run();
}
public void run() throws InterruptedException {
EventLoopGroup client = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(client).channel(NioSocketChannel.class).handler(new ClientHandler());
ChannelFuture future = bootstrap.connect(host == null ? "127.0.0.1" : host, port == 0 ? 6666 : port).sync();
Channel channel = future.channel();
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
String content = scanner.nextLine();
if (content.equals("quit")) {
client.shutdownGracefully();
break;
}
channel.writeAndFlush(content);
}
} finally {
client.shutdownGracefully();
}
}
static class ClientHandler extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast("custom", new ClientCustomHandler());
}
}
static class ClientCustomHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
log.info(msg);
}
}
}