手撸RPC框架 实现自定义网络传输协议

2023年 7月 13日 50.3k 0

大家好,我是小趴菜,接下来我会从0到1手写一个RPC框架,该专题包括以下专题,有兴趣的小伙伴就跟着我一起学习吧

本章源码地址:gitee.com/baojh123/se…

自定义注解 -> opt-01
服务提供者收发消息基础实现 -> opt-01
自定义网络传输协议的实现 -> opt-02
自定义编解码实现 -> opt-03
服务提供者调用真实方法实现 -> opt-04
完善服务消费者发送消息基础功能 -> opt-05
注册中心基础功能实现 -> opt-06
服务提供者整合注册中心 -> opt-07
服务消费者整合注册中心 -> opt-08
完善服务消费者接收响应结果 -> opt-09
服务消费者,服务提供者整合SpringBoot -> opt-10
动态代理屏蔽RPC服务调用底层细节 -> opt-10
SPI机制基础功能实现 -> opt-11
SPI机制扩展随机负载均衡策略 -> opt-12
SPI机制扩展轮询负载均衡策略 -> opt-13
SPI机制扩展JDK序列化 -> opt-14
SPI机制扩展JSON序列化 -> opt-15
SPI机制扩展protustuff序列化 -> opt-16

前言

在上一章中我们实现了服务端收发消息的基础功能,但是细心的同学会发现,我们使用的是Netty自带的String类型的网络传输协议。对于我们自己的RPC框架来说,这种协议不仅性能低下,而且无法扩展。

本章我们将实现我们自己的网络传输协议

设计

说到协议,我们首先会想到HTTP协议,TCP协议等, 以 HTTP协议为例,包括 请求头和 请求体

image.png

HTTP协议的请求头包含以下信息

image.png

  • 请求地址:我们访问的资源目标地址
  • 请求方法:GET,POST,DELETE等
  • 状态:请求的状态码
  • 请求时间:Date
  • 请求体长度:Content-Length
  • 请求类型:Content-Type
  • ..........

HTTP协议的请求体包含以下信息

image.png

请求体就是包含我们这次请求的内容

其实我们可以按照HTTP协议的规则来设计我们自己的协议

实现

新建一个子项目 xpc-rpc-protocol,pom.xml文件如下



    
        xpc-rpc
        com.xpc
        1.0-SNAPSHOT
    
    4.0.0

    xpc-rpc-protocol



既然我们的协议是类似HTTP协议的,那么请求也要包括请求头和 请求体

请求头实现 com.xpc.rpc.protocol.header.RpcHeader

package com.xpc.rpc.protocol.header;

/**
 * 请求头
 */
public class RpcHeader {

    /**
     * 请求类型,是普通请求,或者是心跳消息等
     */
    private String msgType;

    /**
     * 消息体的长度
     */
    private int bodyLen;

    /**
     * 请求的唯一ID
     */
    private Long requestId;


    public String getMsgType() {
        return msgType;
    }

    public void setMsgType(String msgType) {
        this.msgType = msgType;
    }

    public int getBodyLen() {
        return bodyLen;
    }

    public void setBodyLen(int bodyLen) {
        this.bodyLen = bodyLen;
    }

    public Long getRequestId() {
        return requestId;
    }

    public void setRequestId(Long requestId) {
        this.requestId = requestId;
    }
}
  • msgType:请求消息的类型,比如这个请求是普通的请求,就是服务消费者调用服务提供者接口的请求。或者是这个请求是响应请求。还有后续会实现的心跳消息等等
  • bodyLen:请求体数据的长度
  • requestId:这次请求的唯一标识,全局唯一

请求体实现 com.xpc.rpc.protocol.request.RpcRequest

package com.xpc.rpc.protocol.request;

import com.xpc.rpc.protocol.header.RpcHeader;

/**
 * RPC请求体
 */
public class RpcRequest{

    /**
     * 类名称
     */
    private String className;

    /**
     * 方法名称
     */
    private String methodName;

    /**
     * 参数类型数组
     */
    private Class[] parameterTypes;

    /**
     * 参数数组
     */
    private Object[] parameters;


    public RpcHeader getRpcHeader() {
        return rpcHeader;
    }

    public void setRpcHeader(RpcHeader rpcHeader) {
        this.rpcHeader = rpcHeader;
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public Class[] getParameterTypes() {
        return parameterTypes;
    }

    public void setParameterTypes(Class[] parameterTypes) {
        this.parameterTypes = parameterTypes;
    }

    public Object[] getParameters() {
        return parameters;
    }

    public void setParameters(Object[] parameters) {
        this.parameters = parameters;
    }
}
  • className:服务提供者的类名称
  • methodName:这次请求调用的方法
  • parameterTypes:方法参数的类型数组
  • parameters:方法参数数组

响应体实现 com.xpc.rpc.protocol.response.RpcResponse

package com.xpc.rpc.protocol.response;

import com.xpc.rpc.protocol.header.RpcHeader;

/**
 * RPC响应体
 */
public class RpcResponse {

    /**
     * 响应数据
     */
    private T data;

    /**
     * 错误信息
     */
    private String errMsg;

    /**
     * 响应状态码
     */
    private Integer code;
    

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getErrMsg() {
        return errMsg;
    }

    public void setErrMsg(String errMsg) {
        this.errMsg = errMsg;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }
}
  • T:服务消费者调用服务提供者接口,服务提供者接口返回的数据
  • errMsg:如果请求发生异常,返回异常信息
  • code:响应状态码

传输协议 com.xpc.rpc.protocol.ProtocolMessage

package com.xpc.rpc.protocol;

import com.xpc.rpc.protocol.header.RpcHeader;

/**
 * 自定义网络传输协议
 */
public class ProtocolMessage {

    private T t;

    private RpcHeader rpcHeader;

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }

    public RpcHeader getRpcHeader() {
        return rpcHeader;
    }

    public void setRpcHeader(RpcHeader rpcHeader) {
        this.rpcHeader = rpcHeader;
    }
}
  • T:RpcRequest或者是RpcResponse
  • RpcHeader:请求头或者是响应头

结尾

本章我们就实现了自定义的网络传输协议的设计,下一章我们就会使用自定义的协议了来进行网络传输

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论