使用Netty完成一个简单的聊天室服务器端和客户端

本文介绍了使用Java的Netty库创建一个简单的文本聊天应用,包括客户端的连接建立、消息发送与接收,以及服务器端的多通道管理和消息广播。通过NIO事件循环和Channel处理机制,展示了如何实现实时通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

客户端

import java.io.BufferedReader;
import java.io.InputStreamReader;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

//客户端启动类
public class MyChatClient {
	
	public static void main(String[] args) throws InterruptedException, Exception {
		EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
		try {
			Bootstrap bootstarp = new Bootstrap();
			bootstarp.group(eventLoopGroup).channel(NioSocketChannel.class).handler(new MyChatClientInitializer());
			
			ChannelFuture channelFuture = bootstarp.connect("localhost", 8899).sync();
			
			Channel channel = channelFuture.channel();
			
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

			for(;;) {
				channel.writeAndFlush(br.readLine() + "\r\n");
			}
		} finally {
			eventLoopGroup.shutdownGracefully();
		}
	}
}
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

public class MyChatClientInitializer extends ChannelInitializer<SocketChannel> {

	@Override
	protected void initChannel(SocketChannel ch) throws Exception {
		ChannelPipeline pipeline = ch.pipeline();
		
		pipeline.addLast(new DelimiterBasedFrameDecoder(4096, Delimiters.lineDelimiter()));
		pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
		pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
		pipeline.addLast(new MyChatClientHandler());
		
	}

}
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

public class MyChatClientHandler extends SimpleChannelInboundHandler<String> {

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
		System.out.println(msg);
	}

}

服务器端

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

//服务器端
public class MyChatServer {

	public static void main(String[] args) throws InterruptedException {
		EventLoopGroup bossLoopGroup = new NioEventLoopGroup();
		EventLoopGroup workerLoopGroup = new NioEventLoopGroup();
		
		try {
			ServerBootstrap bootstarp = new ServerBootstrap();
			bootstarp.group(bossLoopGroup,workerLoopGroup).channel(NioServerSocketChannel.class)
				.childHandler(new MyChatServerInitializer());
			ChannelFuture channelFuture = bootstarp.bind(8899).sync();
			channelFuture.channel().closeFuture().sync();
		} finally {
			bossLoopGroup.shutdownGracefully();
			workerLoopGroup.shutdownGracefully();
		}
	}
}
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

public class MyChatServerInitializer extends ChannelInitializer<SocketChannel>{

	@Override
	protected void initChannel(SocketChannel ch) throws Exception {
		ChannelPipeline pipeline = ch.pipeline();
		
		pipeline.addLast(new DelimiterBasedFrameDecoder(4096, Delimiters.lineDelimiter()));
		pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
		pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
		pipeline.addLast(new MyChatServerHandler());
		
	}

}
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;

public class MyChatServerHandler extends SimpleChannelInboundHandler<String> {
	
	//channel组
	private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
		Channel channel = ctx.channel();
		
		channelGroup.forEach(ch -> {
			if(ch != channel) {
				ch.writeAndFlush(channel.remoteAddress() +": " +msg + "\n");
			} else {
				ch.writeAndFlush("【自己】: " +msg + "\n");
			}
		});
	}

    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
    	Channel channel = ctx.channel();
    	//向组中成员发送消息
    	channelGroup.writeAndFlush("【服务器】 - "+ channel.remoteAddress() +" 加入\n");
    	//将新建的channel放入分组
    	channelGroup.add(channel);
    }
    
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
    	Channel channel = ctx.channel();
    	//向组中成员发送消息
    	channelGroup.writeAndFlush("【服务器】 - "+ channel.remoteAddress() +"离开\n");
    	//当连接断后将自动清除group中的channel
    }
    
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
    	Channel channel = ctx.channel();
    	
    	channelGroup.writeAndFlush(channel.remoteAddress() +" 上线\n");
    }
    
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
    	Channel channel = ctx.channel();
    	
    	channelGroup.writeAndFlush(channel.remoteAddress() +" 下线\n");
    }
	
	/**
	 * 当出现异常时调用
	 */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
    	cause.printStackTrace();
        ctx.close();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值