【重复造轮子系列】手撸RPC(二)

一、前言

在上一篇文章中我们模仿着Dubbo初步搭建了一个RPC框架,虽然目前什么都没有实现,但是万丈高楼平地起,接下来我们会一步步完善我们的框架。

二、一次RPC的流程是什么样的

在正式编写代码之前我们需要了解的是一次完整的RPC调用是怎么样的。这里我们以ZK为注册中心,UserService作为服务提供方,OrderService做为消费方为例来聊一聊一次完整的RPC调用。

  1. 首先在服务启动的初期服务提供方(UserService)需要将提供的接口注册到ZK上(假设该接口为getUserInfo(Long userId))
  2. 消费方(OrderService)想要获取用户信息所以需要调用UserService。那么就至少需要知道UserSerivce的地址信息(IP+端口),所以OrderService会到ZK中查找对应的信息。
  3. 拿到信息后就要调用UserService对应的方法,在UserService没有提供Http接口的前提下我们怎么调用呢?显然就要用到RPC调用。OrderService通过网络发送对应的请求,UserService收到请求后返回对应的响应,这就是一个简单的RPC调用过程。接下来我们要讨论的是如这个网络请求是如何发送的。

三、在RPC调用中怎么发送网络请求

Java天生是支持网络编程的,想要发送一个网络请求也是比较容易的,下面就是几个方案。

1、最容易想到的就是采用Socket实现BIO模型的网络通信,每次调用之前服务端和消费端都要建立一个Socket,然后通信结束后释放链接,这么做的优缺点都非常明显,优点:模型简单,代码易懂。缺点:效率很低,浪费资源。一个线程处理一个链接。

2、NIO模型,Jdk1.4之后提供了NIO相关API(这里不细谈NIO)。这个方案弥补了方案1缺点,但是NIO的代码相对晦涩难懂。

3、基于Netty实现网络通信,Netty是一个基于事件驱动的NIO框架,提供了相对简单的API屏蔽了Jdk自带NIO晦涩难懂的概念。

综上我们采用Netty作为我们RPC框架的网络模块框架。既然选中了Netty作为网络框架,那么整个网络发送的流程是怎么样的?

  1. 首先我们要知道,作为网络通信一定是有一定的规则的,这个规则我们称之为"通信协议"。所谓的协议,可以认为是一种约定,即服务端和客户端定义好数据是如何解析的。由于在网络传输的过程都是比特流(01010101),所以双方需要约定好如何解读这些数据。
  2. 我们发送的请求在网络中传输的过程中是比特流,所以我们需要将参数进行序列化操作。

这两个是必须的,当然我们也可以在此基础上做一些额外的操作,例如记录日志,压缩等等。下面我们以图的形式来展示。

四、来一次简单的网络通信

1、服务端代码

复制代码
public class ServerTest {

    public static void main(String[] args) throws InterruptedException {
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        //boss 只负责接收请求
        final NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        //worker 负责具体业务
        final NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        final ChannelFuture channelFuture = serverBootstrap.group(bossGroup, workerGroup)
            .channel(NioServerSocketChannel.class)
            .childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(final SocketChannel channel) throws Exception {
                    //服务器初始化
                    channel.writeAndFlush(Unpooled.copiedBuffer("Hello I am Server".getBytes(StandardCharsets.UTF_8)));
                }
            }).bind(8888);
        channelFuture.sync();
        channelFuture.channel().closeFuture().sync();
    }
}

2、客户端代码

复制代码
public class ConsumerTest {

    public static void main(String[] args) throws InterruptedException {
        Bootstrap bootstrap = new Bootstrap();
        EventLoopGroup group = new NioEventLoopGroup();
        bootstrap.group(group).remoteAddress("127.0.0.1",8888).channel(NioSocketChannel.class)
            .handler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(final SocketChannel socketChannel) throws Exception {
                    System.out.println("客户端初始化handler");
                    socketChannel.pipeline().addLast(new SimpleChannelInboundHandler<ByteBuf>() {
                        @Override
                        protected void channelRead0(final ChannelHandlerContext channelHandlerContext,
                            final ByteBuf byteBuf)
                            throws Exception {
                            System.out.println("收到服务端的消息:"+byteBuf.toString(Charset.defaultCharset()));
                        }
                    });
                }
            });
        final ChannelFuture connect = bootstrap.connect();
        final ChannelFuture channelFuture = connect.sync();
        channelFuture.channel().writeAndFlush(Unpooled.copiedBuffer("hello world".getBytes(StandardCharsets.UTF_8)));
        //阻塞,等待接收关闭消息
        channelFuture.channel().closeFuture().sync();
    }
}

3、结果

至此我们已经完成了一次最简单的客户端和服务端的通信,那么接下来要考虑的是如何完成我们的RPC请求呢?这一部分我们放到下一篇中完成

相关推荐
小辰记事本6 小时前
从零读懂RoCEv2数据包构造:从WQE到线缆上的完整旅程
服务器·网络·网络协议·rdma
北京耐用通信7 小时前
全域适配工业场景耐达讯自动化Modbus TCP 转 PROFIBUS 网关轻松实现以太网与现场总线互通
网络·人工智能·网络协议·自动化·信息与通信
在角落发呆8 小时前
Linux转发配置:解锁网络互联的核心密码
linux·运维·网络
YMWM_10 小时前
UDP协议详解:从原理到Python实践
网络·网络协议·udp
pengyi87101511 小时前
共享 IP 与独享 IP 怎么选?被封后升级方案避坑
网络·网络协议·tcp/ip
YuanDaima204811 小时前
Linux 进阶运维与 AI 环境实战:进程管理、网络排错与 GPU 监控
linux·运维·服务器·网络·人工智能
凯勒姆12 小时前
网工网络设备原理及配置
网络·智能路由器
上海云盾-小余13 小时前
网站恶意爬虫拦截策略:智能识别与封禁实操方案
网络·爬虫·安全·web安全
xhbh66613 小时前
网关端口映射和路由器端口转发有什么区别?配置要点全解析
运维·服务器·网络·智能路由器·端口映射·映射·无痕网关
半壶清水13 小时前
用P4 Tutorial、BMv2 和 Mininet‌解析网络第一集------模拟环境搭建
运维·服务器·网络·网络协议·tcp/ip