netty实现多人聊天

要求:当某个客户端与服务端建立连接时,其他客户端会接受到上线消息,连接断开时接受下线消息。并实现一个客户端向其他客户端发生消息的功能。代码和注释如下:

Server:

public class GroupChatServer {

    //监听端口
private int port;

public GroupChatServer(int port) {
this.port = port;
}
//run方法 处理客户端的请求
public void run() throws InterruptedException {
//创建两个线程组
EventLoopGroup boss = new NioEventLoopGroup(1);
EventLoopGroup worker = new NioEventLoopGroup();
try{
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boss, worker).channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//获取pipeline
ChannelPipeline pipeline = socketChannel.pipeline();
//向pipeline加入解码器
pipeline.addLast("decoder", new StringDecoder());
//加入编码器
pipeline.addLast("encoder", new StringEncoder());
//加入自己的业务处理器
pipeline.addLast(new ServerHandler());
}
});
System.out.println("启动");
ChannelFuture future = bootstrap.bind(port).sync();
//监听关闭事件
future.channel().closeFuture().sync();
}
finally {
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}

public static void main(String[] args) throws InterruptedException {
new GroupChatServer(8848).run();
}
}

ServerHandler:
public class ServerHandler extends SimpleChannelInboundHandler<String> {
//定义一个channel组 管理所有channel
//GlobalEventExecutor.INSTANCE是全局事件执行器 单例
private static ChannelGroup channelGroup=new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
//连接建立 一旦连接 第一个被执行 将当前channel加入channelgroup
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
Channel channel =ctx.channel();
//客户端加入聊天的信息发送给其他在线的客户端
channelGroup.writeAndFlush(channel.remoteAddress()+"加入聊天");
channelGroup.add(channel);
}
//表示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 channelHandlerContext, String s) throws Exception {
//获取到当前channel
Channel channel = channelHandlerContext.channel();
//遍历channelGroup
channelGroup.forEach(ch -> {
if ((channel!=ch)){
//不是当前channel则转发消息
ch.writeAndFlush("客户"+channel.remoteAddress()+"内容"+s);
}
else {
ch.writeAndFlush("消息"+s+"已发送");
}
});
}
//断开连接 将xx客户离开信息推送给当前在线的客户
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
channelGroup.writeAndFlush("客户端"+channel.remoteAddress()+"离开");

}
//发生异常

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
//关闭通道
ctx.close();
}
}
Client:
public class GruopChatClient {
//属性
private final String host;
private final int port;

public GruopChatClient(String host, int port) {
this.host = host;
this.port = port;
}
public void run() throws InterruptedException {
EventLoopGroup eventExecutors = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap()
.group(eventExecutors)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//得到pipeline
ChannelPipeline pipeline = socketChannel.pipeline();
//加入相关handler
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast(new ClientHandler());
}
});

ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
Channel channel = channelFuture.channel();
//扫描器
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()){
String s=scanner.nextLine();
//通过channel发送消息
channel.writeAndFlush(s);
}
}
finally {
eventExecutors.shutdownGracefully();
}
}

public static void main(String[] args) throws InterruptedException {
new GruopChatClient("127.0.0.1",8848).run();

}
}
ClientHandler:
public class ClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
System.out.println(s);
}
}


 
posted @ 2020-08-14 00:19  第十八使徒  阅读(396)  评论(0)    收藏  举报