netty搭建socket服务端,接收客户端数据,主动发送数据给客户端

以前项目中用到的netty服务端,现分享出来;

服务端主动发送数据给客户端端,本代码在NioServer类中维护了个map集合用来存储连接的客户端;map的key为客户端发送过来报文中的id(这里你也可以使用ctx.channel().id()相关业务自己实现);

1.netty版本4.1.25

     
        
            io.netty
            netty-all
            4.1.25.Final
        

2.NioServer服务端

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

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Title: NioServer
 * @Description: nio服务端
 * @date 2018/6/415:28
 */
public class NioServer {

  //  private static final Logger logger = LoggerFactory.getLogger(NioServer.class);
    //连接map
    public  static Map map = new HashMap();
    //默认端口
    private Integer defaultPort=8000;
    public void bind(Integer port) throws Exception {
        //配置服务端的NIO线程组
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup) // 绑定线程池
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .option(ChannelOption.SO_KEEPALIVE, true) // 2小时无数据激活心跳机制
                    .childHandler(new ServerChannelInitializer());
            // 服务器异步创建绑定
            if(null==port){
                port=this.defaultPort;
            }
            ChannelFuture f = b.bind(port).sync();
         //   logger.info("服务启动:"+ DateUtils.dateToString(new Date()));
            // 关闭服务器通道
            f.channel().closeFuture().sync();
        } finally {
          //  logger.info("服务停止:"+ DateUtils.dateToString(new Date()));
            // 释放线程池资源
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

3.服务器Channel通道初始化设置


import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
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;

/**
 * @Title: NioServerHandler
 * @Description: 服务器Channel通道初始化设置
 * @date 2018/6/415:29
 */
public class ServerChannelInitializer extends ChannelInitializer {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();

          /* LineBasedFrameDecoder的工作原理是:依次遍历ByteBuf中的可读字节,
        判断看其是否有”\n” 或 “\r\n”, 如果有就以此位置为结束位置。
        从可读索引到结束位置的区间的字节就组成了一行。 它是以换行符为结束标志的解码器,
        支持携带结束符和不带结束符两种解码方式,同时支持配置单行的最大长度,
        如果读到了最大长度之后仍然没有发现换行符,则抛出异常,同时忽略掉之前读到的异常码流。*/
        pipeline.addLast(new LineBasedFrameDecoder(10010));
        //字符串解码和编码
        //LineBasedFrameDecoder + StringDecoder 就是一个按行切换的文本解码器。
        pipeline.addLast( new StringDecoder());
        pipeline.addLast( new StringEncoder());
        //服务器的逻辑
        pipeline.addLast("handler", new NioServerHandler());
    }


}

4.服务端业务实现

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;

import java.util.Date;
/**
 * @Title: NioServerHandler
 * @Description: 服务业务实现
 * @date 2018/6/415:29
 */
public class NioServerHandler  extends SimpleChannelInboundHandler  {
  //  private static final Logger logger = LoggerFactory.getLogger(NioServerHandler.class);

    /**
     *读取客户端发来的数据
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {

        String[] data = msg.toString().split("id=");
        if(data !=null && data.length>1) {
            String[] data1 = data[1].split(";");
            String id = data1[0];
            if (NioServer.map.get(id) != null && NioServer.map.get(id).equals(ctx)) {
                //接收到服务端发来的数据进行业务处理
           //     logger.info("接收数据成功!" + DateUtils.dateToString(new Date()));
            } else {
                //接收到服务端发来的数据进行业务处理
               //如果map中没有此ctx 将连接存入map中
                NioServer.map.put(id, ctx);
             //   logger.info("连接成功,加入map管理连接!"+"mn:" +mn+" " +""+ DateUtils.dateToString(new Date()));
            }
        }else{
            //logger.info(""+"不是监测数据"+ msg.toString()+" "+ DateUtils.dateToString(new Date()));
        }
        // ctx.writeAndFlush("Received your message : " + msg.toString());
    }


/*    *//**
     * 读取完毕客户端发送过来的数据之后的操作
     *//*
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("服务端接收数据完毕..");
        //  ctx.channel().write("");
        //  ctx.channel().flush();
    }*/

    /**
     * 客户端主动断开服务端的链接,关闭流
     * */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(ctx.channel().localAddress().toString() + " 通道不活跃!");
        removeChannnelMap(ctx);
        // 关闭流
        ctx.close();
    }

    /**
     * 客户端主动连接服务端
     * */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
       // logger.info("RemoteAddress"+ ctx.channel().remoteAddress() + " active !");
       // logger.info("msg"+ ctx.m + " active !");
        //  ctx.writeAndFlush("连接成功!");
        super.channelActive(ctx);
    }

    /**
     * 发生异常处理
     * */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
       // logger.error("连接异常,连接异常:"+ DateUtils.dateToString(new Date())+cause.getMessage(), cause);
        ctx.fireExceptionCaught(cause);
     //   removeChannnelMap(ctx);
      //  ctx.close();
    }

  /**
   *删除map中ChannelHandlerContext
   *  */
    private void removeChannnelMap(ChannelHandlerContext ctx){
        for( String key :NioServer.map.keySet()){
            if( NioServer.map.get(key)!=null &&  NioServer.map.get(key).equals( ctx)){
                NioServer.map.remove(key);
            }
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        super.userEventTriggered(ctx, evt);
            if (evt instanceof IdleStateEvent) {
                IdleStateEvent event = (IdleStateEvent) evt;
             if (event.state().equals(IdleState.READER_IDLE))
                     ctx.close();
            //标志该链接已经close 了 
            }
        }

}
 
  

5.启动netty服务端

new Thread(() -> {
            try {
                new NioServer().bind(8000);
            } catch (Exception e) {
                e.printStackTrace();

            }
        }).start();

6.主动发送数据给客户端

NioServer.map.get("客户端报文中唯一id").channel().write(str);
NioServer.map.get("客户端报文中唯一id").channel().flush();

 

你可能感兴趣的:(JAVA应用)