使用Netty實現簡單聊天室功能

    這篇博客主要讀述使用netty實現簡單的聊天室功能 ,當然真正的聊天功能絕對不會這麼簡單,說簡單只是相對於JDK原生的NIO模型來說。理解這個demo你需要對NIO和Netty的流程有一定的瞭解。推薦可以去看一下《Scalable IO in JAVA》

話不多說,來看代碼

Server端代碼

package com.patrick.netty.chat;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

public class ChatServer {

    public static void main(String[] args) {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workGroup = new NioEventLoopGroup();
        ServerBootstrap bootstrap = new ServerBootstrap();
        try {

            bootstrap.group(bossGroup , workGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG , 1024)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline()
                                    .addLast("encoder",new StringEncoder(CharsetUtil.UTF_8))
                                    .addLast("decoder",new StringDecoder(CharsetUtil.UTF_8))
                                    .addLast(new ChatServerHandler());
                        }
                    });
            System.out.println("---------聊天室服務器已啓動-------------");
            ChannelFuture cf =  bootstrap.bind(9000).sync();
            cf.channel().closeFuture().sync();
        } catch (Exception e){
            e.printStackTrace();
        }finally {
            workGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }

    }
}





package com.patrick.netty.chat;

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> {

    private static ChannelGroup defaultChannels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
        Channel connectChannel = channelHandlerContext.channel();

        for (Channel defaultChannel : defaultChannels) {
            if (defaultChannel !=connectChannel) {
                defaultChannel.writeAndFlush("客戶端"+connectChannel.remoteAddress()+"發送信息:"+msg);
            }else{
                defaultChannel.writeAndFlush("服務端"+connectChannel.remoteAddress()+"通知:"+msg);
            }
        }
        System.out.println("客戶端" + connectChannel.remoteAddress() + "發送信息:" + msg);
    }

    /**
     * 監聽客戶端連接情況
     * @param ctx
     * @throws Exception
     */
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Channel channel  = ctx.channel();
        channel.writeAndFlush("客戶端"+channel.remoteAddress()+"已上線");
        defaultChannels.add(channel);
        System.out.println("客戶端"+channel.remoteAddress()+"已上線");

        //向所有客戶端通知上線信息
        for (Channel defaultChannel : defaultChannels) {
            if (defaultChannel !=channel) {
                defaultChannel.writeAndFlush("客戶端"+channel.remoteAddress()+"已上線");
            }
        }


    }

    /**
     * 監聽客戶端斷開情況
     * @param ctx
     * @throws Exception
     */
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Channel channel  = ctx.channel();
        channel.writeAndFlush("客戶端"+channel.remoteAddress()+"下線了");
        System.out.println("客戶端"+channel.remoteAddress()+"下線了");
    }

    /**
     * 異常處理
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.fireExceptionCaught(cause);
    }
}

Client端

package com.patrick.netty.chat;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

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

public class ChatClient {

    public static void main(String[] args) {
        EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        try {
            bootstrap.group(group)  //設置線程組
                    .channel(NioSocketChannel.class) //採用NioSocketChannel作爲客戶端連接通道
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel channel) throws Exception {
                            channel.pipeline()
                                    .addLast("encoder", new StringEncoder(CharsetUtil.UTF_8))
                                    .addLast("decoder", new StringDecoder(CharsetUtil.UTF_8))
                                    .addLast(new ChatClientHandler());
                        }
                    });

            System.out.println("------客戶端已啓動------");
            ChannelFuture channelFuture = bootstrap.connect("localhost", 9000).sync();
            //獲取channel
            Channel channel = channelFuture.channel();
            //往channel中寫數據
            for (; true; ) {
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
                channel.writeAndFlush(bufferedReader.readLine() + "\r\n");
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }

    }
}




package com.patrick.netty.chat;

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

public class ChatClientHandler extends SimpleChannelInboundHandler<String> {

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

    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章