Netty学习之hello world

(一) 说明:

​ 这是一个使用netty框架的demo,客户端发送一个消息到服务端,服务端将消息原样发送到客户端。

(二) 服务端:

(1) netty服务器端的ChannelHandler业务核心处理逻辑

​ 服务器端的处理器Handler命名为HelloWorldChannelHandler,继承自ChannelInboundHandlerAdapter适配器,有如下重载方法:

输入图片说明

我们只实现它的读取方法channelRead和异常处理方法exceptionCaught。

/**
 * 业务核心处理逻辑
 * @author comeCY
 *
 */
public class HelloWorldServerHandler extends ChannelInboundHandlerAdapter{  
    
    /**
     * 读取的方法
     * 覆盖channelRead方法处理所有接收到的数据
     */
    @Override  
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {  
        System.out.println("server channelRead..");  
        //服务端读取
        System.out.println(ctx.channel().remoteAddress()+"->Server :"+ msg.toString());  
        //服务端转发
        ctx.write("server write :"+msg);  
        ctx.flush();  //冲刷
    }  
     
    /**
     * 异常处理
     */
    @Override  
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {  
        cause.printStackTrace();  //打印异常堆栈跟踪
        ctx.close();  //关闭通道
    }  
}

(2) 引导服务器

  • 创建 ServerBootstrap 实例来引导服务器并随后绑定
  • 创建并分配一个 NioEventLoopGroup 实例来处理事件的处理,如接受新的连接和读/写数据。
  • 指定本地 InetSocketAddress 给服务器绑定
  • 通过 EchoServerHandler 实例给每一个新的 Channel 初始化
  • 最后调用 ServerBootstrap.bind() 绑定服务器
public class HelloWorldServer {  
	  
    private int port;  
      
    public HelloWorldServer(int port) {  
        this.port = port;  
    }  
      
    public void start() throws Exception{  
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);  //创建EventLoopGroup
        EventLoopGroup workerGroup = new NioEventLoopGroup();  
        try {  
            ServerBootstrap sbs = new ServerBootstrap()  
              	.group(bossGroup,workerGroup)  //创建ServerBootstrap
                .channel(NioServerSocketChannel.class)  //指定使用 NIO 的传输 Channel
                .localAddress(new InetSocketAddress(port))  //设置 socket 地址使用所选的端口
                .childHandler(new ChannelInitializer<SocketChannel>() {  
                          //添加 到 Channel 的 ChannelPipeline
                        protected void initChannel(SocketChannel ch) throws Exception {  
                          //添加字符串编码和解码器
                            ch.pipeline().addLast("decoder", new StringDecoder());  
                            ch.pipeline().addLast("encoder", new StringEncoder());  
                          //添加 HelloWorldSrverHandler
                            ch.pipeline().addLast(new HelloWorldServerHandler());  
                        };  
                          
                    }).option(ChannelOption.SO_BACKLOG, 128)     
                    .childOption(ChannelOption.SO_KEEPALIVE, true);  //启用心跳保活机制
             // 绑定端口,开始接收进来的连接  
             ChannelFuture future = sbs.bind(port).sync();    
               
             System.out.println("Server start listen at " + port );  
             future.channel().closeFuture().sync();  //关闭 channel 和 块,直到它被关闭
        } finally {
        	bossGroup.shutdownGracefully();  //关闭 EventLoopGroup,释放所有资源
            workerGroup.shutdownGracefully();
        }  
    }  
    
    
    public static void main(String[] args) throws Exception {  
        int port;  
        if (args.length > 0) {  
            port = Integer.parseInt(args[0]);  
        } else {  
            port = 8080;  
        }  
        new HelloWorldServer(port).start();  //呼叫服务器的start方法
    }  
} 

(三) 客户端:

(1) 客户端Handler

HelloWorldClientHandler也是继承自ChannelInboundHandlerAdapter,实现方法channelActive,channelRead,exceptionCaught与服务端类似。

public class HelloWorldClientHandler extends ChannelInboundHandlerAdapter{  
    
    @Override  
    public void channelActive(ChannelHandlerContext ctx) {  
      //当被通知该 channel 是活动的时候打印
        System.out.println("HelloWorldClientHandler Active");  
    }  
  
    @Override  
    public void channelRead(ChannelHandlerContext ctx, Object msg) {  
      //记录接收到的消息
       System.out.println("HelloWorldClientHandler read Message:"+msg);  
    }  
  
   @Override  
   public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {  
       cause.printStackTrace();  //记录日志错误并关闭 channel
       ctx.close();  
    }  
} 

(2) 引导客户端

  • Bootstrap 被创建来初始化客户端
  • NioEventLoopGroup 实例被分配给处理该事件的处理,这包括创建新的连接和处理 入站和出站数据
  • InetSocketAddress 为连接到服务器而创建
  • HelloWorldClientHandler 将被安装在 pipeline 当连接完成时
  • Bootstrap.connect()被调用连接到远程的服务器
public class HelloWorldClient {  
	
	static final String HOST = System.getProperty("host", "127.0.0.1");
	static final int PORT = Integer.parseInt(System.getProperty("port", "8080"));
  
	public static void main(String[] args) throws Exception {
		EventLoopGroup group = new NioEventLoopGroup();
		
		try {
			Bootstrap b = new Bootstrap();  //创建 Bootstrap
          /* 指定 EventLoopGroup 来处理客户端事件。由于我们使用 NIO 传输,所以用到了
NioEventLoopGroup 的实现*/
			b.group(group)  
			    .channel(NioSocketChannel.class)  //使用的 channel 类型是一个用于 NIO 传输
			    .option(ChannelOption.TCP_NODELAY, true)  //关闭Nagle算法,实时发送数据
			    .handler(new ChannelInitializer<SocketChannel>() {

				@Override
				protected void initChannel(SocketChannel ch) throws Exception {
					// TODO Auto-generated method stub
					ChannelPipeline p = ch.pipeline();
					p.addLast("decoder", new StringDecoder());  
                    p.addLast("encoder", new StringEncoder());
					p.addLast(new HelloWorldClientHandler());
				}
			});
			
			ChannelFuture future = b.connect(HOST, PORT).sync();  //连接到远程;等待连接完成
			//客户端写入
			future.channel().writeAndFlush("Hello Netty Server, I am a common client...");
			future.channel().closeFuture().sync();  //阻塞直到 Channel 关闭
		} finally {
			group.shutdownGracefully();  //调用 shutdownGracefully() 来关闭线程池和释放所有资源
		}
	}
}  	

(四) 运行效果:

(1) 服务端

输入图片说明

(2) 客户端

输入图片说明

(五) 结语

学习博客:

参考书籍:

  • netty in action

转载于:https://my.oschina.net/u/3475359/blog/1619607

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值