rpc到自己java实现rpc调用再到rpc框架设计
目录
- rpc(Remote Procedure Call)
- rpc一般架构
- 为什么要引入rpc
- 自己实现rpc调用
- 1. 新建一个maven项目,加入hessian依赖
- 2. 服务端
- 3. Stub代理
- 4. 客户端测试输出
- 5. rpc程序分析
- 附 请求参数和序列化程序
- 6. 总结
- 回顾RPC
- RPC 序列化协议
- RPC 网络协议
- 注册中心的引入
- dubbo框架看一个rpc框架的实现架构
rpc(Remote Procedure Call)
Remote Procedure Call (RPC) is a powerful technique for constructing distributed, client-server based applications. It is based on extending the conventional local procedure calling so that the called procedure need not exist in the same address space as the calling procedure. The two processes may be on the same system, or they may be on different systems with a network connecting them.
rpc一般架构

- 客户端(Client):服务调用方
- 客户端存根(Client Stub):存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息(序列化),再通过网络传输发送给服务端
- Network Service:底层传输,可以是 TCP 或 HTTP,或其它网络协议
- 服务端存根(Server Stub):接收客户端发送过来的请求消息并进行解包(反序列化),然后再调用本地服务进行处理
- 服务端(Server):服务的真正提供者
为什么要引入rpc
两台不同的主机进程要进行通信?
最易想到的最原始做法:tcp/ip通信,二进制数据传输
蛮烦点在于:要写网络相关处理;对方服务进行动态扩展后,客户端又得重新对接处理。最好能能像本地调用localService.doSth()一样,能调用B机器的bService.doSth(), C机器的cService.doSth()
要解决这个问题,提升开发效率,由此开始了rpc的引入,下面通过java编程来完成这一基本目标
自己实现rpc调用
基础知识点如下,其实很基础,就是大一学生学完Java就基本能操作
- JAVA socket编程基础
- JAVA反射
- 代理模式/动态代理
- 序列化
1. 新建一个maven项目,加入hessian依赖
项目结构如下:

- pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.rpc</groupId><artifactId>rpctest</artifactId><version>1.0-SNAPSHOT</version><build><plugins><plugin><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target></configuration></plugin></plugins></build><dependencies><dependency><groupId>com.caucho</groupId><artifactId>hessian</artifactId><version>4.0.38</version></dependency></dependencies></project>
2. 服务端
package com;import com.entity.RpcRequest;
import com.service.impl.ProServiceImpl;
import com.service.impl.UserServiceImpl;
import com.util.HessianSerializerUtil;import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;/*** @Author mubi* @Date 2020/5/18 23:18*/
public class Server {public static void main(String[] args) throws Exception {// 监听指定的端口final int port = 55533;ServerSocket server = new ServerSocket(port);// server将一直等待连接的到来System.out.println("server将一直等待连接的到来");while (true) {Socket client = server.accept();System.out.println("accept client:" + client.getPort());new Thread(() -> {try {// 建立好连接后,从socket中获取客户端传递过来的对象InputStream in = client.getInputStream();RpcRequest rpcRequest = HessianSerializerUtil.deserialize(readInputStream(in));System.out.println("rpcRequest:" + rpcRequest);// 执行方法,// 需要从服务注册中找到具体的类,这里模拟判断Class clazz = null;if (rpcRequest.getClassName().equals("com.service.IUserService")) {clazz = UserServiceImpl.class;}if (rpcRequest.getClassName().equals("com.service.IProService")) {clazz = ProServiceImpl.class;}Method method = clazz.getMethod(rpcRequest.getMethodName(), rpcRequest.getParamTypes());Object o = method.invoke(clazz.newInstance(), rpcRequest.getArgs());// 返回对象 二进制形式发送给客户端OutputStream out = client.getOutputStream();out.write(HessianSerializerUtil.serialize(o));out.flush();client.close();} catch (Exception e) {}}).start();}
// server.close();}public static byte[] readInputStream(InputStream inputStream) throws IOException {byte[] buffer = new byte[2048];int len;ByteArrayOutputStream bos = new ByteArrayOutputStream();while((len = inputStream.read(buffer)) != -1) {bos.write(buffer, 0, len);}return bos.toByteArray();}}
3. Stub代理
package com;import com.entity.RpcRequest;
import com.util.HessianSerializerUtil;import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;/*** @Author mubi* @Date 2020/5/18 23:18*/
public class Stub {public static Object getStub(Class clazz){// 调用方法处理器InvocationHandler h = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 要连接的服务端IP地址和端口final String host = "127.0.0.1";final int port = 55533;// 与服务端建立连接Socket socket = new Socket(host, port);// 构造请求服务器的对象RpcRequest rpcRequest = new RpcRequest(clazz.getName(), method.getName(),method.getParameterTypes(), args);// 传递二进制给服务端OutputStream outputStream = socket.getOutputStream();outputStream.write(HessianSerializerUtil.serialize(rpcRequest));socket.shutdownOutput();// 直接读取服务端返回的二进制, 反序列化为对象返回InputStream inputStream = socket.getInputStream();byte[] bytes = readInputStream(inputStream);Object o = HessianSerializerUtil.deserialize(bytes);inputStream.close();outputStream.close();socket.close();return o;}};Object o = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, h);System.out.println(o.getClass().getInterfaces()[0]);return o;}public static byte[] readInputStream(InputStream inputStream) throws IOException {byte[] buffer = new byte[2048];int len;ByteArrayOutputStream bos = new ByteArrayOutputStream();while((len = inputStream.read(buffer)) != -1) {bos.write(buffer, 0, len);}return bos.toByteArray();}}
4. 客户端测试输出
package com;import com.service.IProService;
import com.service.IUserService;/*** @Author mubi* @Date 2020/5/18 23:18*/
public class Client {public static void main(String[] args) {IUserService iUserService = (IUserService) Stub.getStub(IUserService.class);System.out.println(iUserService.getUserById(12));IProService iProService = (IProService) Stub.getStub(IProService.class);System.out.println(iProService.getProById(12));}}
输出如下:

可以看到客户端使用远程服务像本地服务一样的调用了
5. rpc程序分析
public static Object getStub(Class clazz){// 调用方法处理器InvocationHandler h = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 要连接的服务端IP地址和端口final String host = "127.0.0.1";final int port = 55533;// 与服务端建立连接Socket socket = new Socket(host, port);// 构造请求服务器的对象RpcRequest rpcRequest = new RpcRequest(clazz.getName(), method.getName(),method.getParameterTypes(), args);// 传递二进制给服务端OutputStream outputStream = socket.getOutputStream();outputStream.write(HessianSerializerUtil.serialize(rpcRequest));socket.shutdownOutput();// 直接读取服务端返回的二进制, 反序列化为对象返回InputStream inputStream = socket.getInputStream();byte[] bytes = readInputStream(inputStream);Object o = HessianSerializerUtil.deserialize(bytes);inputStream.close();outputStream.close();socket.close();return o;}};Object o = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, h);System.out.println(o.getClass().getInterfaces()[0]);return o;}
可以看到使用了java动态代理,客户端拿到的ServiceImpl实际上是个代理对象,
调用行为进行了代理,如下几个步骤
- 网络请求socket连接服务端
- 使用hessian将参数 序列化,转化为字节流,进行socket通信
- 服务端socket通信,hessian 反序列化客户端传入的参数,然后反射完成服务的调用,然后 序列化 返回结果
- 客户端收到服务端响应,反序列化结果,输出
附 请求参数和序列化程序
- RpcRequest
package com.entity;import java.io.Serializable;
import java.util.Arrays;/*** rpc请求通用参数结构* @Author mubi* @Date 2020/5/18 23:10*/
public class RpcRequest implements Serializable {String className;String methodName;Class[] paramTypes;Object[] args;public RpcRequest(String className, String methodName, Class[] paramTypes, Object[] args) {this.className = className;this.methodName = methodName;this.paramTypes = paramTypes;this.args = args;}public String getClassName() {return className;}public String getMethodName() {return methodName;}public Class[] getParamTypes() {return paramTypes;}public Object[] getArgs() {return args;}@Overridepublic String toString() {return "RpcRequest{" +"className='" + className + '\'' +", methodName='" + methodName + '\'' +", paramTypes=" + Arrays.toString(paramTypes) +", args=" + Arrays.toString(args) +'}';}
}
- HessianSerializerUtil
package com.util;import com.caucho.hessian.io.HessianInput;
import com.caucho.hessian.io.HessianOutput;
import com.entity.User;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;public class HessianSerializerUtil {public static <T> byte[] serialize(T obj) {byte[] bytes = null;// 1、创建字节输出流ByteArrayOutputStream bos = new ByteArrayOutputStream();// 2、对字节数组流进行再次封装// step 1. 定义外部序列化工厂//ExtSerializerFactory extSerializerFactory = new ExtSerializerFactory();//extSerializerFactory.addSerializer(java.time.OffsetDateTime.class, new OffsetDateTimeRedisSerializer());//extSerializerFactory.addDeserializer(java.time.OffsetDateTime.class, new OffsetDateTimeRedisDeserializer());// step 2. 序列化工厂//SerializerFactory serializerFactory = new SerializerFactory();//serializerFactory.addFactory(extSerializerFactory);HessianOutput hessianOutput = new HessianOutput(bos);//hessianOutput.setSerializerFactory(serializerFactory);try {// 注意,obj 必须实现Serializable接口hessianOutput.writeObject(obj);bytes = bos.toByteArray();} catch (IOException e) {e.printStackTrace();}return bytes;}public static <T> T deserialize(byte[] data) {if (data == null) {return null;}// 1、将字节数组转换成字节输入流ByteArrayInputStream bis = new ByteArrayInputStream(data);// step 1. 定义外部序列化工厂//ExtSerializerFactory extSerializerFactory = new ExtSerializerFactory();//extSerializerFactory.addSerializer(java.time.OffsetDateTime.class, new OffsetDateTimeRedisSerializer());//extSerializerFactory.addDeserializer(java.time.OffsetDateTime.class, new OffsetDateTimeRedisDeserializer());// step 2. 序列化工厂//SerializerFactory serializerFactory = new SerializerFactory();//serializerFactory.addFactory(extSerializerFactory);HessianInput hessianInput = new HessianInput(bis);//hessianInput.setSerializerFactory(serializerFactory);Object object = null;try {object = hessianInput.readObject();} catch (IOException e) {e.printStackTrace();}return (T) object;}static void test() throws Exception{User user = new User(1, "wang");byte[] bytes = HessianSerializerUtil.serialize(user);System.out.println(user);User user1 = HessianSerializerUtil.deserialize(bytes);System.out.println(user1);}public static void main(String[] args) throws Exception {test();}
}
6. 总结
程序其实完成了如下图:

通过最基础的java反射、态代理、socket编程等就实现了简单的类似rpc调用
接下来不管多少种服务;只要双方约定好,客户端直接调用即可,基本不需要修改Stub相关代码; client 调用远程方法,就像调用本地方法一样(客户端同学都不需要懂网络底层,直接服务端有什么,就能用什么)
回顾RPC

RPC 序列化协议
RPC(Remote Procedure Call,远程过程调用)序列化协议是用于在网络上传输数据的一种机制,特别是在客户端和服务器之间传输函数调用请求和响应时。序列化是将数据结构或对象状态转换为可以存储或传输的格式的过程。在RPC通信中,序列化是关键步骤,因为它使得数据能够在网络上安全传输并被另一端正确解析。
常见的序列化协议包括json、xml、hession、protobuf、thrift、text、bytes等;
-
JSON是一种轻量级的数据交换格式,易于阅读和编写,支持跨语言使用。然而,JSON的序列化和反序列化速度较慢,且序列化后的数据体积较大,不适合对性能要求较高的场景
-
Protobuf:由谷歌开发,支持多语言平台,序列化后的数据体积小,序列化速度快。它需要预编译IDL文件,适用于需要高效数据传输和存储的场景
-
Thrift:由Facebook开发,支持跨语言服务开发,序列化速度快,数据体积小。Thrift既是传输协议也是序列化协议,适用于需要高效数据处理的分布式系统
-
Hessian:主要用于Web服务的序列化和反序列化,支持跨语言调用,但相对于其他协议,Hessian的性能略逊一筹
RPC 网络协议
如下通信协议
- TCP/UDP
- Web Service
- Restful(http + json)
- RMI(Remote Method Invocation)
- JMS(Java Message Service)
- RPC(Remote Procedure Call)
不过本质还是掌握Socket编程,了解网络IO相关知识
注册中心的引入
随着服务数量的增多,各个服务之间的调用变得错综复杂,一个服务可能依赖外部多个服务,当一个服务的域名或IP地址改变了之后如何通知依赖方,或者依赖方如何快速的发现服务提供方的地址变化。
两种方案:
- 客户端与服务端自己维护:有多少个服务,客户端就要维护多少个(服务增减,负载均衡,心跳)
- 找个代理,客户端有需求找代理,代理维持这些服务,也能给客户通知;(可以看成
代理模式)

显然是注册中心的方式更加合理和方便。
服务中心可以进行服务注册,类似维护一个登记簿,它管理系统内所有的服务地址。当新的服务启动后,它会向登记簿交待自己的地址信息。服务的依赖方直接向登记簿要Service Provider地址就行了,或者基于某种约定(负载均衡)拿到服务的一个具体实例进行通信就好了
回顾springboot+dubbo+zookeeper的注册服务和调用实践:https://blog.csdn.net/qq_26437925/article/details/145790590
dubbo框架看一个rpc框架的实现架构

相关文章:
rpc到自己java实现rpc调用再到rpc框架设计
目录 rpc(Remote Procedure Call)rpc一般架构为什么要引入rpc自己实现rpc调用1. 新建一个maven项目,加入hessian依赖2. 服务端3. Stub代理4. 客户端测试输出5. rpc程序分析附 请求参数和序列化程序 6. 总结 回顾RPCRPC 序列化协议RPC 网络协议注册中心的引入dubbo框…...
Milvus向量数据库可视化客户端Attu
概述 关于Milvus的介绍,可搜索网络资料。Milvus的使用还在摸索中;打算写一篇,时间待定。 关于Attu的资料: 官网GitHub文档 对于Milvus的数据可视化,有如下两个备选项: Milvus_cli:命令行工…...
CSS `transform` 属性详解:打造视觉效果与动画的利器
CSS transform 属性详解:打造视觉效果与动画的利器 引言一、transform 属性简介二、平移(Translation)三、旋转(Rotation)四、缩放(Scale)五、倾斜(Skew)六、组合变换&am…...
【落羽的落羽 数据结构篇】顺序结构的二叉树——堆
文章目录 一、堆1. 概念与分类2. 结构与性质3. 入堆4. 出堆 二、堆排序三、堆排序的应用——TOP-K问题 一、堆 1. 概念与分类 上一期我们提到,二叉树的实现既可以用顺序结构,也可以用链式结构。本篇我们来学习顺序结构的二叉树,起个新名字—…...
基于STM32的智能农业大棚环境控制系统
1. 引言 传统农业大棚环境调控依赖人工经验,存在控制精度低、能耗高等问题。本文设计了一款基于STM32的智能农业大棚环境控制系统,通过多参数环境监测、作物生长模型与精准执行控制,实现大棚环境的智能优化,提高作物产量与品质。…...
Git常见命令--助力开发
git常见命令: 创建初始化仓库: git 将文件提交到暂存区 git add 文件名 将文件提交到工作区 git commit -m "注释(例如这是发行的版本1)" 文件名 查看状态 如果暂存区没有文件被提交显示: $ git status On…...
一:将windows上的Python项目部署到Linux上,并使用公网IP访问
windows中python的版本:python3.13.1,项目使用的是虚拟环境解释器 linux系统:仅有python3.6.7 服务器:阿里云服务器有公网IP,访问端口XXXX 在linux上安装python3.13.1 linux中如果是超级管理员root,执行所…...
1_2 流浪地球(python)
1.题目 分值:100 题目描述 流浪地球计划在赤道上均匀部署了N个转向发动机,按位置顺序编号为0~N-1。 初始状态下所有的发动机都是未启动状态。 发动机启动的方式分为“手动启动”和“关联启动”两种方式如果在时刻1一个发动机被启动,下一个时…...
【数据标准】数据标准化是数据治理的基础
导读:数据标准化是数据治理的基石,它通过统一数据格式、编码、命名与语义等,全方位提升数据质量,确保准确性、完整性与一致性,从源头上杜绝错误与冲突。这不仅打破部门及系统间的数据壁垒,极大促进数据共享…...
计算机视觉:经典数据格式(VOC、YOLO、COCO)解析与转换(附代码)
第一章:计算机视觉中图像的基础认知 第二章:计算机视觉:卷积神经网络(CNN)基本概念(一) 第三章:计算机视觉:卷积神经网络(CNN)基本概念(二) 第四章:搭建一个经典的LeNet5神经网络(附代码) 第五章࿱…...
七星棋牌顶级运营产品全开源修复版源码教程:6端支持,200+子游戏玩法,完整搭建指南(含代码解析)
棋牌游戏一直是移动端游戏市场中极具竞争力和受欢迎的品类,而七星棋牌源码修复版无疑是当前行业内不可多得的高质量棋牌项目之一。该项目支持 6大省区版本(湖南、湖北、山西、江苏、贵州),拥有 200多种子游戏玩法,同时…...
编程考古-忘掉它,Delphi 8 for the Microsoft .NET Framework
忘掉它吧,作一篇记录! 【圣何塞,加利福尼亚 – 2003年11月3日】在今日的Borland开发者大会上,Borland正式推出了Delphi 8 for Microsoft .NET Framework。这款新版本旨在为Delphi开发者提供一个无缝迁移路径,将现有的…...
宠物智能可穿戴产品调研报告
一、引言 随着人们生活水平的提高以及情感陪伴需求的增长,宠物在家庭中的地位愈发重要,宠物经济蓬勃发展。宠物智能可穿戴产品作为宠物市场与科技融合的新兴领域,正逐渐走进大众视野,为宠物饲养与管理带来新的变革。本调研旨在深…...
[通俗易懂C++]:指针和const
之前的文章有说过,使用指针我们可以改变指针指向的内容(通过给指针赋一个新的地址)或者改变被保存地址的值(通过给解引用指针赋一个新值): int main() {int x { 5 }; // 创建一个整数变量 x,初始值为 5int* ptr { &x }; // 创建一个指针 ptr,指向 …...
大一高数(上)速成:导数和微分
目录 1.分段函数的可导性: 2.隐函数求导: 3.参数方程求导: 4.对数求导法: 5.函数的微分: 1.分段函数的可导性: 2.隐函数求导: 3.参数方程求导: 4.对数求导法: 5.函数的微分:...
使用 DeepSeek 和 Google Gemini 算命
目录 DeepSeek 调用Gemini 调用基础 PromptFAQ1. Gemini 返回失败2. DeepSeek 超时 DeepSeek 调用 由于 DeepSeek API 是兼容 openai 的,所以直接使用 openai 的 sdk 即可。 // Please install OpenAI SDK first: npm install openaiimport OpenAI from openai; i…...
京东cfe滑块 分析
声明: 本文章中所有内容仅供学习交流使用,不用于其他任何目的,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关! 逆向分析 headers {"accept&qu…...
list结构刨析与模拟实现
目录 1.引言 2.C模拟实现 2.1模拟实现结点 2.2模拟实现list前序 1)构造函数 2)push_back函数 2.3模拟实现迭代器 1)iterator 构造函数和析构函数: *操作符重载函数: 前置/后置/--: /!操作符重载…...
react 踩坑记 too many re-renders.
报错信息: too many re-renders. React limits the number of randers to prevent an infinite loop. 需求 tabs只有特定标签页才展示某些按钮 button要用 传递函数引用方式 ()>{} *还有要注意子组件内loading触发 导致的重复渲染...
BGP分解实验·19——BGP选路原则之起源
当用不同的方式为BGP注入路由时,起源代码将标识路由的来源。 (在BGP表中,Network为“i”,重分布是“?”) 实验拓扑如下: R2上将来自IGP的路由10.3.3.3/32用network指令注入BGP;在R4上将来自I…...
二叉树中每个节点能到达的最远距离
一、题目描述 输入一个只包含0和1的字符串表示二叉树,输出每个节点能到达的最远距离,通过父节点的路径也要考虑。 比如输入"111110000010000", 输出[3,2,4,3,3,4]。 1A / \ 1B 1C / \ / \ 1D 1E 0 0 / \ /…...
单机上使用docker搭建minio集群
单机上使用docker搭建minio集群 1.集群安装1.1前提条件1.2步骤指南1.2.1安装 Docker 和 Docker Compose(如果尚未安装)1.2.2编写docker-compose文件1.2.3启动1.2.4访问 2.使用2.1 mc客户端安装2.2创建一个连接2.3简单使用下 这里在ubuntu上单机安装一个m…...
结构体简介
前言 这篇文章呢就给大家简单讲解一下什么是结构体,也让大家对结构体有一个较为清晰的了解,从而帮助同学们更好的掌握结构体。 结构体类型的声明 结构的声明 在声明结构体的类型是,先给大家拓展两个重要的关键字 typedef 和 struct. 拓展…...
家用路由器的WAN口和LAN口有什么区别
今时今日,移动终端盛行的时代,WIFI可以说是家家户户都有使用到的网络接入方式。那么路由器当然也就是家家户户都不可或缺的设备了。而路由器上的两个实现网络连接的基础接口 ——WAN 口和 LAN 口,到底有什么区别?它们的功能和作用…...
实操解决Navicat连接postgresql时出现‘datlastsysoid does not exist‘报错的问题
1 column “datlastsysoid“ does not exist2 Line1:SELECT DISTINCT datalastsysoid FROM pg_database问题分析 Postgres 15 从pg_database表中删除了 datlastsysoid 字段引发此错误。 决绝方案 解决方法1:升级navicat 解决方法2:降级pgsql 解决方…...
3分钟idea接入deepseek
DeepSeek简介 DeepSeek 是杭州深度求索人工智能基础技术研究有限公司开发的一系列大语言模型,背后是知名量化资管巨头幻方量化3。它专注于开发先进的大语言模型和相关技术,拥有多个版本的模型,如 DeepSeek-LLM、DeepSeek-V2、DeepSeek-V3 等&…...
树莓派理想二极管电路分析
如果 Vin Vout,比如说 5.0V,PNP 晶体管以当前的镜像配置偏置。晶体管 U14 的 Vb 将为 5-0.6 4.4V,镜像配置意味着 Vg 也将为 4.4V. Vgs 为4.4-5.0 -0.6V。mosfet 将处于关闭状态(几乎打开)。如果 Vout 略低于 Vin&a…...
关于在mac中配置Java系统环境变量
引言 在 macOS 上开发 Java 或 Flutter 应用时,正确配置环境变量是至关重要的。环境变量不仅能让系统找到开发工具的位置,还能简化命令行操作。本文将手把手教你从零开始安装 Java SDK,并详细配置环境变量,涵盖常见问题解决和优化…...
Unity贴图与模型相关知识
一、贴图 1.贴图的类型与形状 贴图类型 贴图形状 2.在Unity中可使用一张普通贴图来生成对应的法线贴图(但并不规范) 复制一张该贴图将复制后的贴图类型改为Normal Map 3.贴图的sRGB与Alpha sRGB:勾选此选项代表此贴图存储于Gamma空间中…...
Linux--进程(进程虚拟地址空间、页表、进程控制、实现简易shell)
一、进程虚拟地址空间 这里以kernel 2.6.32,32位平台为例。 1.空间布局 在 32 位系统中,虚拟地址空间大小为 4GB。其中: 内核空间:占据高地址的 1GB ,用于操作系统内核运行,包含内核代码、内核数据等&am…...
