Netty的群发实现2

下面代码需要talent 进行模拟客户端。采用的是netty4.1.16 JDK1.8

我用的Xshell一样可以实现

具体代码实现如下

package qunfa;

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

public class NettyServer {

    public void bing(int port) throws Exception {

        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workGroup);
            b.channel(NioServerSocketChannel.class);
            b.option(ChannelOption.SO_BACKLOG, 1024);
            b.childHandler(new ChildChannelHandler());

            // 绑定端口
            ChannelFuture f = b.bind(port).sync();

            // 等待服务端监听端口关闭
            f.channel().closeFuture().sync();

        } finally {
            // 优雅的退出
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }
    public static void main(String[] args) {
        try {
            System.out.println("服务端开启等待客户端链接");
            new NettyServer().bing(2333);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
 
  
package qunfa;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

public class ChildChannelHandler extends ChannelInitializer {

    @Override
    protected void initChannel(SocketChannel e) throws Exception {

        System.out.println("报告");
        System.out.println("信息:有一客户端链接到本服务端");
        System.out.println("IP:" + e.localAddress().getHostName());
        System.out.println("Port:" + e.localAddress().getPort());
        System.out.println("报告完毕");

        // 解码器
        // 以"\n"或者"\r\n"作为分隔符,解决粘包和半包问题
        e.pipeline().addLast(new LineBasedFrameDecoder(1024));

        // 基于指定字符串【换行符,这样功能等同于LineBasedFrameDecoder,以/r/n或者/n作为分隔符】
        //e.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, false, Delimiters.lineDelimiter()));
        // 基于最大长度
        //e.pipeline().addLast(new FixedLengthFrameDecoder(4));
        e.pipeline().addLast(new StringDecoder());
        e.pipeline().addLast(new StringEncoder());
        e.pipeline().addLast(new MyServerHanlder());
    }
}

 
  
package qunfa;

import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;

/**
 *
 * 这里讲ChannelGroup单独放到一个类里,并有多个客户端使用
 * 同时ChannelGroup是static的
 * 说明:这不是唯一的处理方式
 *
 */
public class MyChannelHandlerPool {

    public static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

}

 
  
package qunfa;

import java.util.Date;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

//public class MyServerHanlder extends ChannelHandlerAdapter{
public class MyServerHanlder extends ChannelInboundHandlerAdapter{

    /*
    * channelAction
    *
    * channel 通道
    * action 活跃的
    *
    * 当客户端主动链接服务端的链接后,这个通道就是活跃的了。也就是客户端与服务端建立了通信通道并且可以传输数据
    *
    */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {

        System.out.println(ctx.channel().localAddress().toString() + " channelActive");

        //添加到channelGroup 通道组
        MyChannelHandlerPool.channelGroup.add(ctx.channel());

        //通知已经链接上客户端 回写数据
        String str = "您已经开启与服务端链接" + " " + ctx.channel().id() + new Date() + " " + ctx.channel().localAddress();
        ctx.writeAndFlush(str);
    }

    /*
    * channelInactive
    *
    * channel 通道
    * Inactive 不活跃的
    *
    * 当客户端主动断开服务端的链接后,这个通道就是不活跃的。也就是说客户端与服务端的关闭了通信通道并且不可以传输数据
    *
    */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {

        // 从channelGroup中移除,当有客户端退出后,移除channel。
        MyChannelHandlerPool.channelGroup.remove(ctx.channel());

        System.out.println(ctx.channel().localAddress().toString() + " channelInactive");
    }

    /*
    * channelRead
    *
    * channel 通道
    * Read 读
    *
    * 简而言之就是从通道中读取数据,也就是服务端接收客户端发来的数据
    * 但是这个数据在不进行解码时它是ByteBuf类型的后面例子我们在介绍
    *
    */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        //注意此处已经不需要手工解码了,将信息显示在控制台
        System.out.println(ctx.channel().id() + "" + new Date() + " " + msg);

        //通知您已经链接上客户端[给客户端穿回去的数据加个换行]
        String str = "服务端收到:" + ctx.channel().id() + new Date() + " " + msg + "\r\n";

        //收到信息后,群发给所有小伙伴
        MyChannelHandlerPool.channelGroup.writeAndFlush(str);
    }

    /*
    * channelReadComplete
    *
    * channel 通道
    * Read 读取
    * Complete 完成
    *
    * 在通道读取完成后会在这个方法里通知,对应可以做刷新操作
    * ctx.flush()
    *
    */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    /*
    * exceptionCaught
    *
    * exception异常
    * Caught抓住
    *
    * 抓住异常,当发生异常的时候,可以做一些相应的处理,比如打印日志、关闭链接
    *
    */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
        System.out.println("异常信息:\r\n"+cause.getMessage());
    }
}


你可能感兴趣的:(Netty)