2(实战):Netty从入门到网络通信实战(文末有项目连接)

建议前置阅读:Netty框架
https://www.jianshu.com/nb/49815762

Netty 介绍
1:Netty 是一个基于 NIO (同步非阻塞)的 client-server(客户端服务器)框架,:
2:简化了 TCP 和 UDP 套接字服务器等网络编程,且性能以及安全性等很多方面更好。
3:支持多种协议如 HTTP,FTP,SMTP, 以及各种二进制和基于文本的传统协议。

Netty 特点
1:统一的 API,支持多种传输类型,阻塞和非阻塞的。
2:简单而强大的线程模型。
3:自带编解码器解决 TCP 粘包/拆包问题。自带各种协议栈。
4:真正的无连接数据包套接字支持。
5:比直接使用 Java 核心 API 有更高的吞吐量、更低的延迟、更低的资源消耗和更少的内存复制。
6:安全性不错,有完整的 SSL/TLS 以及 StartTLS 支持。
7:社区活跃成熟稳定,经历了大型项目的使用和考验,而且很多开源项目都使用到了 Netty 比如我们经常接触的 Dubbo、RocketMQ 等等。

Netty的作用?    
1:作为 RPC 框架的网络通信工具 : 我们在分布式系统中,不同服务节点之间经常需要相互调用:调用另外一个节点的方法的话,至少是要让对方知道调用的是哪个类中的哪个方法以及相关参数;
2:实现一个自己的 HTTP 服务器:类似于Tomcat:最基本的 HTTP 服务器可要以处理常见的 HTTP Method 的请求,比如 POST 请求、GET 请等等
3:实现一个即时通讯系统(QQ/微信)
4:消息推送(物联网(IOT)消息推送)

Netty 入门实战
1:定义客户端与服务端进行交互的实体类:RpcRequest RpcResponse
    public class RpcRequest {
        private String interfaceName;
        private String methodName;
    }

    public class RpcResponse {
       private String message;
    }

2:编写客户端
客户端主要有一个用于向服务端发送消息的sendMessage()方法:
可以通过这个方法将RpcRequest对象发送给服务端,并且可以同步获取服务端返回的RpcResponse对象;
  
流程
    1:首先初始化了一个 Bootstrap
             1:指定线程组
             2:指定IO模型
             3:自定义业务处理逻辑
                
    2:通过 Bootstrap 对象连接服务端
    
    3:writeAndFlush 通过 Channel 向服务端发送请求消息  (RpcRequest)    
    4:channelRead  通过 Channel 接收的响应信息(RpcResponse) 存放到 Channel 的AttributeKey   
   
    5:等待连接关闭(阻塞,直到Channel关闭)
    
    6:从Channel 的AttributeKey拿返回的结果 RpcResponse
    //尝试连接并获取 Channel  
    ChannelFuture f = bootStrap.connect(host, port).sync();
    Channel futureChannel = f.channel();

    //发送消息 并 阻塞等待
    if (futureChannel != null) {
        futureChannel.writeAndFlush(rpcRequest).addListener(future -> {    
                if (future.isSuccess()) {        
                 logger.info("client send message: [{}]", rpcRequest.toString());    
                } else {       
                    logger.error("Send failed:", future.cause());   
                }
         });
         
         // 等待连接关闭(阻塞,直到Channel关闭)
         futureChannel.closeFuture().sync();
         
         //Channel继承了AttributeMap 也就是Channel具有AttributeMap的相关属性
         // 将服务端返回的数据也就是RpcResponse对象取出
         AttributeKey key = AttributeKey.valueOf("rpcResponse");
         return futureChannel.attr(key).get();
     }     
    //NettyClientHandler的channelRead方法  对 RpcResponse 进行处理

    // NettyClientHandler用户读取服务端发送过来的RpcResponse消息*
    //将RpcResponse消息对象保存到AttributeMap上
    //AttributeMap可以看做是Channel的共享数据源;

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
    try {
        RpcResponse rpcResponse = (RpcResponse) msg;
        logger.info("client receive msg: [{}]", rpcResponse.toString());
        // 声明一个 AttributeKey 对象
        AttributeKey key = AttributeKey.valueOf("rpcResponse");
        // 将服务端的返回结果保存到 AttributeMap 上,AttributeMap 可以看作是一个Channel的共享数据源
        // AttributeMap的key是AttributeKey,value是Attribute
        ctx.channel().attr(key).set(rpcResponse);
        ctx.channel().close();
    } finally {
        ReferenceCountUtil.release(msg);
    }
}

3:编写服务端
主要用于开启一个服务端并接收客户端的请求并处理

流程:
    1:首先初始化了一个 ServerBootstrap
             1:指定两个线程组   EventLoopGroup (bossGroup workerGroup)
             2:指定IO模型 
             3:自定义业务处理逻辑
                
    2:通过 ServerBootstrap 对象连接服务端
    
    3:channelRead  通过 Channel 接收     客户端的请求信息 (RpcRequest)  
    4:writeAndFlush 通过 Channel 返回      响应信息(RpcResponse)到客户端
    
    5:等待连接关闭(阻塞,直到Channel关闭)
    //尝试连接并获取 Channel  
    ChannelFuture f = serverBootstrap.bind(port).sync();
    Channel futureChannel = f.channel();
    
    // 等待连接关闭(阻塞,直到Channel关闭)
    futureChannel.closeFuture().sync();

  //NettyClientHandler的channelRead方法  对 RpcRequest 进行处理
  public void channelRead(ChannelHandlerContext ctx, Object msg) {
        try {
            RpcRequest rpcRequest = (RpcRequest) msg;
            logger.info("server receive msg: [{}] ,times:[{}]", rpcRequest, atomicInteger.getAndIncrement());
            RpcResponse messageFromServer = RpcResponse.builder().message("message from server").build();
            ChannelFuture f = ctx.writeAndFlush(messageFromServer);
            f.addListener(ChannelFutureListener.CLOSE);
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }

项目连接

请配合项目代码食用效果更佳:
项目地址:
https://github.com/hesuijin/rpc-project
Git下载地址:
https://github.com.cnpmjs.org/hesuijin/rpc-project.git

rpc-project-demo模块下  nettyDemo包

你可能感兴趣的:(2(实战):Netty从入门到网络通信实战(文末有项目连接))