netty 的学习

客户端代码:
public class Server {
	  private int port;
	    
	    public Server(int port) {
	        this.port = port;
	    }
	    
	    public void run() throws Exception {
	        EventLoopGroup bossGroup = new NioEventLoopGroup(); // 创建线程组监听端口
	        EventLoopGroup workerGroup = new NioEventLoopGroup();//创建线程组来处理客户端发来的消息
	        try {
	            ServerBootstrap b = new ServerBootstrap(); // 是一个帮助类 用来开启服务
	            b.group(bossGroup, workerGroup)
	             .channel(NioServerSocketChannel.class) // (3)
	             .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
	                 @Override
	                 public void initChannel(SocketChannel ch) throws Exception {
	                	//每次有新的连接进来 都会创建新的ChannelPipeline 所以ServerHandler 不存在线程问题
	                	 System.out.println("初始化了");
	                	 ChannelPipeline pipeline = ch.pipeline();
	                	//加心跳机制
	                	pipeline.addLast("ping", new IdleStateHandler(3, 0, 0,TimeUnit.SECONDS));
	                	//加解码器
	                	pipeline.addLast("decode",new DecodeMessgae());
	                	//加处理器
	                	pipeline.addLast("handler",new ServerHandler());  
	                	
	                 }
	             })
	             .option(ChannelOption.SO_BACKLOG, 128)          // (5)
	             .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
	    
	            // Bind and start to accept incoming connections.
	            ChannelFuture f = b.bind(port).sync(); // (7) //同步
	                
	            // Wait until the server socket is closed.
	            // In this example, this does not happen, but you can do that to gracefully
	            // shut down your server.
	            f.channel().closeFuture().sync();//同步 如果不关闭,线程会一直阻塞
	        } finally {
	            workerGroup.shutdownGracefully();
	            bossGroup.shutdownGracefully();
	        }
	    }
	    
	    public static void main(String[] args) throws Exception {
	        int port;
	        if (args.length > 0) {
	            port = Integer.parseInt(args[0]);
	        } else {
	            port = 2000;
	        }
	        new Server(port).run();
	    }
} 

解码器:

 public class DecodeMessgae extends ByteToMessageDecoder {

	@Override
	protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
		int length = in.readableBytes();
		//如果不输出 那么会一直调用decode方法 继续去读 直到 直到输出结果才会把缓冲的数据丢弃到并且会自动释放ByteBuf内存
		if(length < 6){
			System.out.println("当前length:"+length+"b不够");
			return ;
		}else{
			byte[] body = new byte[in.readableBytes()];
		    in.readBytes(body);
			String s = new String(body);
			out.add(body);
		}
		
	}


}

处理消息:

public class ServerHandler extends ChannelInboundHandlerAdapter {

	private int counter = 0;

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		System.out.println(this.hashCode() + "有客户端连接");
	}
    
	
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		try{
		System.out.println("开始读取进来了");
		
		}finally {
			  //ReferenceCountUtil.release(msg); 如果不用解码器 一定要手动释放 写数据是 netty会帮我们释放ByteBuf
		}
		
	}
	
	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		System.out.println("--- Client is inactive ---");
	}
     
	
	//根据心跳机制前面设置的时间 会执行下面的代码	
    //IdleState.READER_IDLE 读空闲
	//IdleState.WRITER_IDLE 写空闲
	//IdleState.ALL_IDLE 读写空闲
	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		super.userEventTriggered(ctx, evt);
	
		if (evt instanceof IdleStateEvent) {
			counter++;
		}
		if(counter > 4){
			ctx.channel().close();
			System.out.println("关闭当前连接");
		}
		
	}
    
	   /**
     * 处理心跳包
     *
     * @param ctx
     * @param packet
     */
    private void handleHeartbreat(ChannelHandlerContext ctx, Object msg) {
        // 将心跳丢失计数器置为0
        counter = 0;
        System.out.println("收到心跳包");
      
    }
    
    /**
     * 处理数据包
     *
     * @param ctx
     * @param packet
     */
    private void handleData(ChannelHandlerContext ctx, Object msg) {
        // 将心跳丢失计数器置为0
        counter = 0;
        
    }
	
}
@Override
    public void channelActive(final ChannelHandlerContext ctx) throws Exception {
    	System.out.println("有新的客户端连接");
    	final ByteBuf time = ctx.alloc().buffer(4);
    	time.writeInt((int) (System.currentTimeMillis() / 1000L + 2208988800L));
    	final ChannelFuture f = ctx.writeAndFlush(time);
    	System.out.println("状态1:"+f.isDone());
    	//当ChannelFuture完成后 才执行 是异步执行的 如果ChannelFuture没完成 这个监听事件的代码
    	//不会执行
    	f.addListener(new ChannelFutureListener() {	
			public void operationComplete(ChannelFuture future) throws Exception {
				// TODO Auto-generated method stub
				System.out.println("状态2:"+future.isDone());
				System.out.println("关闭客户端");
			    assert f == future;
			    ctx.close();
			}
		});
    }

 解决粘包和拆包的解码器代码:

import java.util.List;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

public class DecodeMessgae extends ByteToMessageDecoder {
  
	
	//数据格式  前缀(4) + 长度 (4)+数据 
	
	private int baseLength = 4 + 4;
     

	@Override
	protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
		int length = in.readableBytes();
		//如果不输出 那么会一直调用decode方法 继续去读 直到 直到输出结果才会把缓冲的数据丢弃到并且会自动释放ByteBuf内存
		if(length < baseLength){
			return ;
		}
		
		//如果出现大数据直接过滤掉 根据需要填写字段
		if(length > 30){
			in.skipBytes(length);
			return;
		}
		
		//读取包头位 只有包头正确 继续读取数据
		int beginReader = 0;
		while(true){
			beginReader = in.readerIndex();
			in.markReaderIndex();
			int pre = in.readInt();
			System.out.println(pre);
			if(pre == 2){
				break;
			}
			in.resetReaderIndex();
			//每次只前进一位
			in.readByte();
	       
			//读取之后长度变的不满足
			if(in.readableBytes() < baseLength){
				return ;
			}
		}
		//读取数据大小
		int dataLength = in.readInt();
		if(in.readableBytes() < dataLength){
			//还原读指针
			in.readerIndex(beginReader);
			return ;
		}
		
	
        byte[] bs = new byte[dataLength];
		in.readBytes(bs);
		String s = new String(bs);
		out.add(s);
		
		
		
	}


}

测试代码:

    

public class Client2 {

	public static void main(String[] args) throws Exception {

		Socket s = new Socket("127.0.0.1", 2000);
		Scanner in = new Scanner(System.in);
		while (in.hasNext()) {
			String data = in.nextLine();
			ByteBuffer byteBuffer = ByteBuffer.allocate(4 + 4 + 4 + data.length());
			byteBuffer.putInt(55);
			byteBuffer.putInt(2);
			byteBuffer.putInt(data.length());
			byteBuffer.put(data.getBytes());
			byte[] array = byteBuffer.array();
			s.getOutputStream().write(array);
			s.getOutputStream().flush();

		}
		in.close();
        s.close();
        
	}

}



猜你喜欢

转载自blog.csdn.net/hyhanyu/article/details/80452691
今日推荐