美文网首页netty
netty学习三:基于socket的聊天小demo

netty学习三:基于socket的聊天小demo

作者: Sam同学 | 来源:发表于2017-08-02 09:16 被阅读0次

    服务端代码

    package chat.server;
    
    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 ChatServer {
    
        public static void main(String[] args) throws InterruptedException {
            // 接收连接,但是不处理
            EventLoopGroup parentGroup = new NioEventLoopGroup();
            // 真正处理连接的group
            EventLoopGroup childGroup = new NioEventLoopGroup();
            
            try {
                //加载Initializer
                ServerBootstrap serverBootstrap = new ServerBootstrap();
                serverBootstrap.group(parentGroup, childGroup)
                               .channel(NioServerSocketChannel.class)
                               //这里的childHandler是服务于childGroup的,如果直接使用
                               //handler方法添加处理器,则是服务于parentGroup的
                               .childHandler(new ChatServerInitializer());
                
                //绑定监听端口
                ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
                channelFuture.channel().closeFuture().sync();
            }
            finally {
                parentGroup.shutdownGracefully();
                childGroup.shutdownGracefully();
            }
        }
    }
    
    package chat.server;
    
    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 ChatServerInitializer extends ChannelInitializer<SocketChannel>{
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            ChannelPipeline pipeline = ch.pipeline();
            
            //1、按照分隔符切割消息
            pipeline.addLast(new DelimiterBasedFrameDecoder(4096,Delimiters.lineDelimiter()));
    
            //2、socket编程中需要对字符串进行编码解码
            pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
            pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
            
            pipeline.addLast(new ChatServerHandler());
        }
    }
    
    package chat.server;
    
    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 ChatServerHandler 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 (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.writeAndFlush("有人:"+channel.remoteAddress()+"加入\n");
            
            channelGroup.add(channel);
        }
        
        @Override
        public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
            Channel channel = ctx.channel();
            channelGroup.writeAndFlush("有人:"+channel.remoteAddress()+"离开\n");       
        }
        
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            Channel channel = ctx.channel();
            System.out.println(channel.remoteAddress() + "上线");
        }
        
        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            Channel channel = ctx.channel();
            System.out.println(channel.remoteAddress() + "上线");
        }
        
    }
    

    客户端代码

    package chat.client;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    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 ChatClient {
    
        public static void main(String[] args) throws InterruptedException, IOException {
            EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
            
            try {
                //加载Initializer
                Bootstrap bootstrap = new Bootstrap();
                bootstrap.group(eventLoopGroup)
                               .channel(NioSocketChannel.class)
                               .handler(new ChatClientInitializer());
                
                //连接服务端
                Channel channel = bootstrap.connect("localhost", 8899).sync().channel();
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                for(;;) {
                    channel.writeAndFlush(br.readLine() + "\r\n");
                }
            }
            finally {
                eventLoopGroup.shutdownGracefully();
            }
        }
    }
    
    package chat.client;
    
    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 ChatClientInitializer extends ChannelInitializer<SocketChannel>{
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
    ChannelPipeline pipeline = ch.pipeline();
            //1、按照分隔符切割消息
            pipeline.addLast(new DelimiterBasedFrameDecoder(4096,Delimiters.lineDelimiter()));
    
            //2、socket编程中需要对字符串进行编码解码
            pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
            pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
            
            //3、添加自定义处理器
            pipeline.addLast(new ChatClientHandler());
        }
    }
    
    package chat.client;
    
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.SimpleChannelInboundHandler;
    
    public class ChatClientHandler extends SimpleChannelInboundHandler<String>{
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
            System.out.println(msg);
        }
    }
    
    

    当有新的客户端连接到服务器的时候,ChatServerHandler的channelRead0方法会给所有上线的客户端发送消息。

    ChatClient的main方法中,会从System.in中获取用户的输入,并写到服务端。

    csdn code 路径


    这个项目的源代码放置在csdn code上,欢迎访问。

    netty_study

    相关文章

      网友评论

        本文标题:netty学习三:基于socket的聊天小demo

        本文链接:https://www.haomeiwen.com/subject/nekelxtx.html