Netty聊天实现
<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.42.Final</version> </dependency>
public class NettyServer { public static void main(String[] args) throws Exception { //创建两个线程组bossGroup和workerGroup, 含有的子线程NioEventLoop的个数默认为cpu核数的两倍 // bossGroup只是处理连接请求 ,真正的和客户端业务处理,会交给workerGroup完成 EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { //创建服务器端的启动对象 ServerBootstrap bootstrap = new ServerBootstrap(); //使用链式编程来配置参数 bootstrap.group(bossGroup, workerGroup) //设置两个线程组 .channel(NioServerSocketChannel.class) //使用NioServerSocketChannel作为服务器的通道实现 // 初始化服务器连接队列大小,服务端处理客户端连接请求是顺序处理的,所以同一时间只能处理一个客户端连接。 // 多个客户端同时来的时候,服务端将不能处理的客户端连接请求放在队列中等待处理 .option(ChannelOption.SO_BACKLOG, 1024) .childHandler(new ChannelInitializer<SocketChannel>() {//创建通道初始化对象,设置初始化参数 @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast("decoder",new StringDecoder()); ch.pipeline().addLast("encoder",new StringEncoder()); //对workerGroup的SocketChannel设置处理器 ch.pipeline().addLast(new NettyServerHandler()); } }); System.out.println("聊天室启动成功。。"); //绑定一个端口并且同步, 生成了一个ChannelFuture异步对象,通过isDone()等方法可以判断异步事件的执行情况 //启动服务器(并绑定端口),bind是异步操作,sync方法是等待异步操作执行完毕 ChannelFuture cf = bootstrap.bind(9000).sync(); //对通道关闭进行监听,closeFuture是异步操作,监听通道关闭 //通过sync方法同步等待通道关闭处理完毕,这里会阻塞等待通道关闭完成 cf.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } }
public class NettyServerHandler extends SimpleChannelInboundHandler<String> { //存储所有连接的channel private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); // 表示channel 处于就绪状态,提示上线 @Override public void channelActive(ChannelHandlerContext ctx) throws Exception{ Channel channel = ctx.channel(); channelGroup.writeAndFlush("[客户端]"+channel.remoteAddress()+"上线了"+ sdf.format(new java.util.Date())); channelGroup.add(channel); System.out.println(ctx.channel().remoteAddress()+"上线了"); System.out.println("在线人数:"+channelGroup.size()); } //表示channel处于不活动状态,提示离线了 @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { Channel channel =ctx.channel(); //将客户离开信息推送给当前在线用户 channelGroup.writeAndFlush("【客户端】"+channel.remoteAddress()+"离线了\n"); System.out.println(ctx.channel().remoteAddress()+"下线了"); System.out.println("在线人数:"+channelGroup.size()); } /** * 读取客户端发送的数据 * * @param ctx 上下文对象, 含有通道channel,管道pipeline * @param s 就是客户端发送的数据 * @throws Exception */ protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception { final Channel channel = ctx.channel(); channelGroup.forEach(ch->{ if(channel!=ch){ ch.writeAndFlush("【客户端】"+channel.remoteAddress()+"发送消息:"+s+"\n"); }else{ ch.writeAndFlush("【自己】发送了消息:"+s+"\n"); } }); } /** * 处理异常, 一般是需要关闭通道 * * 89 * @param ctx * * @param cause * * @throws Exception * */ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.close(); } }
public class NettyClient { public static void main(String[] args) throws Exception { //客户端需要一个事件循环组 EventLoopGroup group = new NioEventLoopGroup(); try { //创建客户端启动对象 //注意客户端使用的不是 ServerBootstrap 而是 Bootstrap Bootstrap bootstrap = new Bootstrap(); //设置相关参数 bootstrap.group(group) //设置线程组 .channel(NioSocketChannel.class) // 使用 NioSocketChannel 作为客户端的通道实现 .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel channel) throws Exception { channel.pipeline().addLast(new StringDecoder()); channel.pipeline().addLast(new StringEncoder()); //加入处理器 channel.pipeline().addLast(new NettyClientHandler()); } }); //启动客户端去连接服务器端 ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 9000).sync(); Channel channel = channelFuture.channel(); System.out.println("客户端启动成功:" + channel.localAddress() ) ; Scanner scanner =new Scanner(System.in); while (scanner.hasNextLine()){ String msg = scanner.nextLine(); channel.writeAndFlush(msg); } //对关闭通道进行监听 channelFuture.channel().closeFuture().sync(); } finally { group.shutdownGracefully(); } } }
public class NettyClientHandler extends SimpleChannelInboundHandler<String>{ @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception { System.out.println(s.trim()); } }