Netty——聊天室/入站和出战

  • 聊天室实现
  • 实验过程
  • 过程分析
  • 入站和出战

1. 聊天室实现

  • 服务端启动类:MyChatServer
    • 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 Exception{
              EventLoopGroup bossGroup = new NioEventLoopGroup();
              EventLoopGroup workGroup = new NioEventLoopGroup();
      
              try {
                  ServerBootstrap serverBootstrap = new ServerBootstrap();
                  serverBootstrap.group(bossGroup,workGroup).channel(NioServerSocketChannel.class).
                          childHandler(new MyChatServerInitailizer());
                  ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
                  channelFuture.channel().closeFuture().sync();
              } finally {
                  bossGroup.shutdownGracefully();
                  workGroup.shutdownGracefully();
              }
          }
      }
  • 服务端initChannel:MyChatServerInitailizer

    • 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 MyChatServerInitailizer extends ChannelInitializer<SocketChannel> {
          @Override
          protected void initChannel(SocketChannel ch) throws Exception {
              ChannelPipeline pipeline = ch.pipeline();
              pipeline.addLast(new DelimiterBasedFrameDecoder(4096,Delimiters.lineDelimiter()));  //负责按/r/n拆包
              pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));//Byte自动转String
              pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));//Byte自动转String
              pipeline.addLast(new MyChatServerHandler());//Inbound类型Handler
          }
      }
  • 服务端Handler: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;
      
      import java.text.SimpleDateFormat;
      import java.util.Date;
      
      public class MyChatServerHandler extends SimpleChannelInboundHandler<String> {
      
          private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
      
          @Override
          protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
              final Channel channel = ctx.channel();
              channelGroup.forEach(ch->{
                  if(channel != ch){
                      ch.writeAndFlush(channel.remoteAddress()+"发送消息:"+msg+"\n");
                  }else{
                      ch.writeAndFlush("【自己】"+msg+"\n");
                  }
              });
          }
      
          @Override
          public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
              Channel channel = ctx.channel();
              channelGroup.add(channel);
              System.out.println(new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss:SSS").format(new Date()) +  "————handlerAdded执行:");
              channelGroup.writeAndFlush("【服务器】-"+channel.remoteAddress()+"加入\n");
          }
      
          @Override
          public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
              Channel channel = ctx.channel();
              System.out.println(new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss:SSS").format(new Date()) +  "————handlerRemoved执行:");
              channelGroup.writeAndFlush("【服务器】-"+channel.remoteAddress()+"离开\n");
          }
      
          @Override
          public void channelActive(ChannelHandlerContext ctx) throws Exception {
              Channel channel = ctx.channel();
              System.out.println(new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss:SSS").format(new Date()) +  "————channelActive执行:");
              System.out.println(channel.remoteAddress()+"上线");
          }
      
          @Override
          public void channelInactive(ChannelHandlerContext ctx) throws Exception {
              Channel channel = ctx.channel();
              System.out.println(new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss:SSS").format(new Date()) +  "————channelInactive执行:");
              System.out.println(channel.remoteAddress()+"下线");
          }
      
          @Override
          public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
              cause.printStackTrace();
              ctx.close();
          }
      }
  • 客户端启动类:MyCahtClient

    • import java.io.BufferedReader;
      import java.io.InputStreamReader;
      import io.netty.bootstrap.Bootstrap;
      import io.netty.channel.Channel;
      import io.netty.channel.EventLoopGroup;
      import io.netty.channel.nio.NioEventLoopGroup;
      import io.netty.channel.socket.nio.NioSocketChannel;
      
      public class MyCahtClient {
          public static void main(String[] args) throws Exception{
              EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
              try {
                  Bootstrap bootstrap = new Bootstrap();
                  bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
                          .handler(new MyCahtClientInitailizer());
                  Channel channel = bootstrap.connect("localhost",8899).channel();
                  BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                  for(;;){
                      channel.writeAndFlush(br.readLine()+"\r\n");
                  }
              }finally {
                  eventLoopGroup.shutdownGracefully();
              }
          }
      }
  • 客户端MyChatServerInitailizer

    • 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 MyCahtClientInitailizer 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());
          }
      }
  • 客户端Handler:MyChatClientHandler

    • import io.netty.channel.ChannelHandlerContext;
      import io.netty.channel.SimpleChannelInboundHandler;
      
      import java.text.SimpleDateFormat;
      import java.util.Date;
      
      public class MyChatClientHandler extends SimpleChannelInboundHandler<String> {
          @Override
          protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
              System.out.println(new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss:SSS").format(new Date()) + "————" +msg);
          }
      }

2. 实验过程

  1. 先起了服务端
  2. 起了三个客户端
  3. 客户端1 发送了两条数据
  4. 关闭客户端3
  5. 截图

服务端:

客户端1:

客户端2:

3.过程分析

  • 从服务端的角度
    • 启动了serverBootstrap引导类,绑定了Handler,绑定端口8899,等待连接
    • client启动,执行到 channel.writeAndFlush(); 但还未输入文字
    • 此时channel已经打开,Server先后执行了,handlerAdded(),channelActive()方法
    • 待补充

4.入站和出站

  • 如果是Client输入msg到Server,即Client写出(走Client的OutboundHandler),Server读入(走Server的InboundHandler)。

  • 如果是Server把某个client的msg发给各个client,即Server写入(走Server的InboundHandler),Client读入(走Client的InboundHandler)

  • 总结
    • 1. 入站操作主要是指读取数据的操作;而出站操作主要是指写入数据的操作
      2. 入站会从先读取,再执行入站的Handler;出站会先执行出站的Handler,再写入
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值