《WebKit 技术内幕》学习之十(2): 插件与JavaScript扩展

news2024/9/24 11:29:12

2 Chromium PPAPI插件

2.1 原理

        插件其实是一种统称,表示一些动态库,这些动态库根据定义的一些标准接口可以跟浏览器进行交互,至于这个标准接口是什么都可以,重要的是大家都遵循它们,NPAPI接口标准只是其中的一种,因为它被广泛使用,所以被提到的次数也最多。本节介绍的PPAPI也是一种浏览器和插件交互的接口标准,该标准是由Google提出,在Chromium项目中获得支持。

        PPAPI的提出是因为NPAPI的可移植性和性能存在比较大的问题,特别是针对跨进程的插件,同时还有插件需要2D和3D绘图、声音等问题时候就更为棘手。早期的阶段就是要解决这些问题,同时为了赢得插件厂商的支持,尽可能地使用原来NPAPI的接口。现在,随着PPAPI的不断发展,接口不断发生改变。后来,PPAPI也被用在Native Client技术中,之后也被逐渐地修改,直到现在的样子,完整的列表可以查看链接http://code.google.com/p/ppapi/w/list。

        那么,为什么PPAPI能够提供较高性能的绘图和声音等解决方案呢?前面我们提到,在现在的NPAPI插件系统中,通常的做法是,当网页需要显示该插件的时候或者需要更新的时候,它会发送一个失效(Invalidate)的通知,让插件来绘制它们。而在PPAPI插件机制中,它引入了一个保留(Retained)模式,其含义是浏览器始终保留一个后端存储空间,用来表示上一次绘制完的区域。这个很有用,因为PPAPI插件通常是跨进程的,所以浏览器可以绘制网页而不需要锁,与此同时插件进程能够在后台绘制新的结果。

        PPAPI插件有两种运行模式,受信(Trusted)插件和非受信(Untrusted)插件。对于受信的PPAPI插件,它可以在Renderer进程中运行,也可以在另外的进程中运行。对于新版本的实现,架构设计都是基于IPC来设计的。对于非受信的PPAPI插件,则可以借助于使用NativeClient技术来安全运行。受信插件是与平台相关的,可以调用平台相关的接口。而对于非受信插件而言,它们可以是与平台无关的代码,可以调用NativeClient提供的有限接口,而不能调用其他接口,这个后面再介绍。

        在Chromium中,NPAPI和PPAPI插件同时得到支持,都可以在“chrome://plugins”来查看,前面已经提到过。有趣的是,对于同一个功能的插件,甚至可能有两个不同的版本,如图10-8所示Flash的NPAPI插件和PPAPI插件实现。

                        图10-8 Chrome浏览器的NPAPI插件和PPAPI插件

        PPAPI插件同样使用“embed”或者“object”元素,这让网页看起来没什么大的区别,所以对于WebKit而言,它根本不会区分背后的是NPAPI插件还是PPAPI插件,差别在于调用的接口不一样而已,这样做的好处显而易见。

2.2 结构和接口

2.2.1 代码结构

        因为PPAPI插件对于WebKit而言是透明的,所以这里不再介绍WebKit中支持该插件的基础设施。Chromium支持跨进程的PPAPI插件机制,所以在代码结构上可以充分看到这一点。Chromium项目中有3个目录用来支持这一机制,详细结构如图10-9所示。

                        图10-9 支持PPAPI插件机制的代码目录结构

        首先是chrome目录,它包含Renderer进程和Browser进程对于PPAPI插件的支持代码,主要是资源的实现类。

        其次是content目录,同样也包含了资源的实现类,但是同时也有支持跨进程机制的代码,这会在后面的工作过程图中有所体现。

        最后是ppapi目录,当然支持PPAPI插件的代码都是在该目录中,包括支持跨进程的基础代码,它们被Renderer进程和Browser进程的支持代码所使用。

        读者可能好奇为什么chrome目录下的相关文件不直接放在content/目录下,这主要取决于Chromium项目的层次化结构。content目录下包含一些公共或者基础的设施,而chrome/目录则是跟浏览器密切相关的。例如对于PPAPI插件机制而言,它将PDF和Flash都放在该目录下,而将文件等放在content目录下。

2.2.2 应用程序编程接口

        同NPAPI的NPN和NPP开头的接口相似,PPAPI也需要双向调用的编程接口,PPAPI提供了浏览器调用插件的接口,同时更是提供了众多插件调用浏览器各种功能的接口,这非常不一样,因为功能更为强大。

        这些接口的标准定义文件都位于上面所述的目录ppapi/api中,它们都使用一种接口定义语言(IDL,Interface Definition Language)来描述。IDL是一种标准,有兴趣的读者可以查阅它的基本语法。其中以ppb_(ppapi browser)开头的接口文件表示这是由浏览器实现,被插件库所调用;以ppp_(ppapi plugin)开头的接口文件表示这是由插件实现,被浏览器所调用;而其他以pp_开头的接口文件表示共享的接口定义,两边都需要使用,主要是一些基础类定义等。

        不同于NPAPI只是提供C接口,PPAPI既提供了C接口,同时又提供了C++接口。C接口主要是函数指针和结构为主,而C++接口则是提供各种作用的类,它们分别位于目录ppapi/c和ppapi/cpp下。因为两个定义的功能是一致的,之后我们都以C++接口为例来解释PPAPI插件机制。

        公共部分的接口包括各个基础数据,如时间、大小、矩形和资源,这些类会作为后面定义接口的参数来传递,对应的接口例如PP_Time、PP_Size、PP_Rect和PP_Resource。这里面非常重要的接口是PP_Resource,它表示各种类型的资源,例如文件资源、音频资源、图像资源、图形资源等。

        由插件实现的接口大致包括以下几个部分:第一部分是插件模块和插件实例,用于初始化和关闭插件的管理插件功能的接口,例如PPP_InitializeModule()、PPP_ShutdownModule()。而插件的实例类,表示一个插件的实例对象,也就是Interface PPP_Instance,这里面包含多个函数,如DidCreate、DidDestroy等,表示当创建插件之后,浏览器调用它们,以便插件能够做一些后续的辅助工作。第二部分是一些事件的通知接口,表示浏览器需要派发一些消息给插件,典型的包括鼠标事件、通用消息传递接口、3D图形上下文丢失事件和鼠标锁定事件等。

        由浏览器实现的接口,主要提供各种能力给插件使用,这其中包括2D和3D图形绘制接口、文件IO、文件系统、鼠标事件、网络、游戏手柄、时间等,这些都是PPAPI机制中定义的可以被浏览器调用的资源及其编程接口,读者会发现这些主要都是为游戏的需求服务的,实际上这些机制就是为了高性能的游戏而设计的。

2.3 工作过程

2.3.1 基础设施

        对于PPAPI插件的跨进程架构,同NPAPI插件的跨进程架构非常类似,可以说基本相同。同样当网页中出现一个“embed”元素的时候,PPAPI插件进程会为它创建一个插件实例,这里不再赘述。

        对于插件模块和实例接口,由插件进程直接调用并根据需要加载和创建它们,非常的简单明了。在PPAPI插件机制中,复杂的是资源的调用,也就是浏览器提供给插件使用的各种资源接口,所以下面重点介绍围绕资源的基础设施。

        图10-10描述了跨进程模式下PPAPI插件机制中资源是如何被插件调用的。如同前面一样,PPAPI的插件是在插件进程中被加载的,当它需要使用插件的时候,通过图中Thunk设施将C接口转成C++接口来调用相应的PluginResource类。该类是所有资源的基类,是一个代理类(只是将请求转发给真正的实现者),负责发送请求给其他进程,拥有接受其他进程发过来的调用结果的能力。发送请求由相应的其他类来帮助,在这里是PluginDispatcher类和HostDispatcher类。它们都会使用IPC::Channel来发送消息,消息会被Browser进程和Renderer进程中的BrowserPpapiHost类和RenderPpapiHost类处理(它们依赖ppapi/host的基类),这些请求会发送给ResourceHost类来处理,以调用真正的实现函数。读者发现这两个进程都有ResourceHost的子类,这是因为某些资源的实现在Renderer进程完成,例如2D和3D图形资源,但是有些类必须在Browser进程中处理,如文件和文件系统等。

                图10-10 跨进程的PPAPI插件机制中支持资源的基础设施

2.3.2 工作过程

        这里以Chromium中PPAPI的一个使用2D绘图的例子来说明PPAPI插件的工作过程,该例子位于目录ppapi/examples/2d下,主要有两个部分,一个是个简单的HTML网页文件(2d.html),另外一个就是实现插件的文件(paint_manager_example.cc)。示例代码10-1是使用插件的网页代码,示例代码主要是“embed”元素,同NPAPI插件的使用方式完全一模一样,下面会逐步讲解PPAPI插件的源代码,以及该插件是如何和该网页一起工作的。

示例代码10-1 使用插件的网页代码

    <html>
    <head>
        <title>2D Example</title>
    </head>
    <body>
        <embed id="plugin" type="application/x-ppapi-example-2d">
    </body>
    </html>

        首先当然是插件的创建过程。在WebKit中,对于PPAPI和NPAPI的支持都是类似的,所以可以回顾10-7中的NPAPI插件被创建的过程,二者同样根据MIME类型来查找PPAPI插件机制,如果Chromium发现查找到的是一个PPAPI插件而不是NPAPI插件,那么在创建WebPluginContainerImpl对象的时候,就会首先创建一个WebPlugin子类的对象。注意,这里不是一个WebPluginImpl对象,而是一个PepperWebPluginImpl对象。之后它就发送消息到插件进程,请求创建一个插件的实例。回到插件进程,它会根据插件的注册信息查找需要的插件并调用它的构造函数来初始化该插件的模块,如示例代码10-2所示的CreateModule方法。之后需要调用该方法返回的对象来创建一个插件实例的对象,如示例代码中的CreateInstance方法,会创建一个插件类自定义的一个示例。

示例代码10-2 插件的实现代码部分节选

    class MyModule : public pp::Module {
        public:
         virtual pp::Instance* CreateInstance(PP_Instance instance) {
           return new MyInstance(instance);
         }
    };
    namespace pp {
         Module* CreateModule() {
           return new MyModule();
         }
    }

        根据示例代码10-2和示例代码10-3,当MyInstance被创建的时候,Chromium会创建PPP_Proxy_Instance对象,该对象接收从Renderer进程传递过来的关于该实例的状态消息,如插件视图改变、销毁等,然后再调用插件的相应接口,前面说过这些接口是在插件中实现并由浏览器调用的。

        其次来了解资源的创建,一个插件实例可能会用到多个资源,如绘图资源、文件资源等,示例代码10-3所示的OnPaint函数使用到了2D绘图资源。由于它使用了PaintManager类,当需要更新视图的时候,该类需要创建一个Graphics2D资源对象。

示例代码10-3 插件的实例类自定义实现

    class MyInstance : public pp::Instance, public pp::PaintManager::Client {
     public:
      MyInstance(PP_Instance instance) {
        …
      }
      virtual bool HandleInputEvent(…) { … }
      virtual void OnPaint(pp::Graphics2D& graphics_2d, …) { … }
     private:
      pp::PaintManager paint_manager_;
    };

        为了详细说明它的调用过程,图10-11和图10-12描述了资源类对象的创建和资源类对象接口的调用过程,分别以插件进程和Renderer进程的交互为例,而插件进程和Browser进程的交互则是类似的情况。

                        图10-11 Chromium创建PPAPI插件的资源对象的过程

        图10-11包括两个步骤,第一个步骤在插件进程中完成,第二个步骤在Renderer进程中完成。当PPAPI插件需要创建一个资源对象的时候,会通过PPAPI的C接口调用Chromium内部的实现,Thunk层将其转换成C++风格的调用。在插件进程中,会有一个工厂类来创建不同类型的资源对象。本例中Graphics2DResource对象在创建的同时会发送一个消息到Renderer进程,这就是第二步骤。Renderer进程同样包含一个能够创建不同类型ResourceHost对象的工厂类,以帮助完成资源对象的创建。

                        图10-12 PPAPI插件调用资源对象接口的过程

                图10-12描述了当资源对象创建完之后,插件需要调用资源对象的接口来完成特定的操作,这一过程可以包含三个步骤,其发生在两个进程中,图中已有完整描述。首先,当然还是插件进程接收到插件的调用请求,并把请求发送给Renderer进程。其次是Renderer进程接收响应,然后执行特定的操作,并将结果值返回或者通知插件进程该动作执行完成。最后是插件进程接收到返回值或者动作执行完的消息,如果需要,它还可以调用插件的函数来通知插件。当然,某些调用不需要从Renderer进程返回结果到插件进程,所以前两步是必需的,但是第三步却是可选的。

2.4 Native Client

2.4.1 基本原理

        NativeClient,也简称为NaCl,是一种沙箱技术,它能够提供给平台无关的不受信本地代码一个安全的运行环境,可以针对那些计算密集型的需求,例如游戏引擎、可视化计算、大数据分析、3D图形渲染等,这些场合只需要访问有限的一些本地接口,不需要通过网络服务来计算,以免占用额外的带宽资源。同时,它能够比较方便地将原来使用传统语言例如C++编写的库直接移植到Web平台中。它同WebGL、WebAudio这样的技术所解决的问题相似,但是途径不同,因为这些技术是规范(或者草案),而NativeClient技术是Google提出的。使用NativeClient能够将很多本地库的能力轻易地提供给网页使用,而不需要复杂的移植过程,给重用带来很大的方便。

        本身PPAPI和NativeClient没有必然联系,两者解决的是不同方面的问题:PPAPI提供插件机制;NativeClient使用PPAPI的插件机制将使用NativeClient技术编译出来的本地库运行同浏览器交互起来。只是目前NativeClient是基于PPAPI接口来实现的,其实之前NativeClient也曾经基于NPAPI接口来实现,所以能够在Firefox、Safari和Opera浏览器中运行(目前显然不能了)。

        因为NativeClient使用PPAPI来提供一个安全的运行环境,本身它也是一个PPAPI插件,图10-13就是Chrome浏览器中一个PPAPI插件——NativeClient。同其他的PPAPI插件不一样,它是一个在Renderer进程中运行的插件,因为这个插件显然是受信的,如图中的“Type: PPAPI(in-process)”。

                                图10-13 NativeClient的PPAPI插件

        所以,如果需要在网页加入代码<embed id="plugin" type="application/x-nacl">表明使用了NaCl技术,对于WebKit而言,它就是调用一个插件(不知是什么类型的插件),对于PPAPI技术而言,它就是调用了内嵌的NaCl PPAPI插件。因为NaCl还需要调用开发者的本地库,所以它还需要跟本地库来交互,下面来介绍PPAPI插件之后的技术。

        NaCl本质上是一个运行环境,该子系统提供了很少的一些受限系统调用接口和资源的抽象,本地库只能调用它们,而不能任意使用系统调用。与沙箱模型的不同在于,NaCl是将一个第三方开发的代码库运行在受限的环境中,而沙箱模型是将一个进程运行在受限环境中。NaCl提供编译工具,将使用C/C++代码编写的代码编译生成它能运行的可执行格式——nexe。本地代码调用的也都是本地接口,同JavaScript的交互都由NaCl机制和PPAPI机制来完成。

        为了直观理解NaCl机制,用图10-14描述了它的架构图,该图参考Chromium官方网站的示意图,为进行了一些删减和修改。

                        图10-14 使用PPAPI技术的NaCl机制

        首先研究一下Renderer进程,如果没有后面的部分,NaCl插件和其他PPAPI插件没有什么特别的差别,同样通过PPAPI跟渲染引擎进行通信。但是这里NaCl插件只是一个桥接工作,它将同浏览器(也可以说渲染引擎)的交互交接到使用NaCl技术的本地可执行库“nexe”。

        然后,Chromium会创建一个新的进程,该进程使用了沙箱技术,只能访问特定的系统接口,这样限定了该进程中的任何库都不能超越它们。在Renderer进程中的NaCl插件使用消息传递机制同sel_ldr进程通信。在消息机制之上是一种称为SPRC(简单的进程远程调用技术),该机制可以实现PPAPI的跨进程调用。不过目前插件同NaCl的实现之间的通信机制SRPC已经不支持,都是通过一个新的接口PostMessage来实现的,该接口意味着都是通过消息机制来进行的。

        最后,sel_ldr提供的环境能够运行nexe,从图10-14中可以看出,nexe是不受信的部分,但是没关系,该机制可以用一个沙箱来将它运行在限定的sel_ldr进程中,nexe没有办法使用NaCl提供的接口之外的系统接口,从而保证了安全。nexe是本地代码库,所以跟平台相关,例如对于32位和64位系统,需要两份不同的代码库,这同时也造成了库的冗余,有没有什么好的办法能够解决这个问题呢?在最近的版本中,Google的工程师开始将LLVM技术引入到NaCl机制中,这就是pNaCl技术。

2.4.2 pNaCI

        nexe需要不同的版本,一个关键的问题在于NaCl提供的编译工具只能将NaCl的实现直接编译成同硬件架构相关的本地代码,所以不同的平台需要生成不同的本地库。pNaCl提供了一套新的工具,该工具能够将C/C++代码编译成LLVM字节码,读者回忆一下图9-27中关于LLVM的基本结构,LLVM能够将C/C++代码转成字节码,该字节码是平台无关的,而且该字节码可以保存起来,当字节码在某个平台上运行的时候,LLVM的后端能够根据字节码生成特定平台的本地代码。

        回到pNaCl上来,使用了LLVM技术很明显地能够带来减少库的冗余性的好处,这样nexe就可以变成pexe(portable exe)。对于如何使用pNaCl,这里不再介绍,官方网站上有非常详细的介绍,感兴趣的读者请查阅下面的网页:http://www.chromium.org/nativeclient/pnacl/developing-pnacl。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1404031.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C# CefSharp 输入内容,点击按钮,并且滑动。

前言 帮别人敲了个Demo,抱试一试心态&#xff0c;居然成功了&#xff0c;可以用。给小伙伴们看看效果。 遇到问题 1&#xff0c;input输入value失败&#xff0c;里面要套了个事件&#xff0c;再变换输入value。后来用浏览器开发工具&#xff0c;研究js代码&#xff0c;太难了&a…

IMX6ULL|GPIO子系统

一.GPIO子系统 GPIO是General Purpose I/O的缩写&#xff0c;即通用输入输出端口&#xff0c;简单来说就是MCU/CPU可控制的引脚&#xff0c;这些引脚通常有多种功能&#xff0c;最基本的是高低电平输入检测和输出&#xff0c;部分引脚还会与主控器的片上外设绑定&#xff0c;如…

Spring Boot3整合knife4j(swagger3)

目录 1.前置条件 2.导依赖 3.配置 1.前置条件 已经初始化好一个spring boot项目且版本为3X&#xff0c;项目可正常启动。 作者版本为3.2.2最新版 2.导依赖 knife4j官网&#xff1a; Knife4j 集Swagger2及OpenAPI3为一体的增强解决方案. | Knife4j (xiaominfo.com)http…

Unity - 简单音频

“Test_04” AudioTest public class AudioTest : MonoBehaviour {// 声明音频// AudioClippublic AudioClip music;public AudioClip se;// 声明播放器组件private AudioSource player;void Start(){// 获取播放器组件player GetComponent<AudioSource>();// 赋值…

Django ORM 中高级单表查询 API(2)

Django ORM 中的单表查询 API&#xff08;1&#xff09;https://blog.csdn.net/Python_1981/article/details/135653173 在上一篇博文中&#xff0c;我们探讨了 Django ORM 中单表查询 API 的基础知识&#xff0c;重点是 all()、filter()、get()、first() 和 last()。在…

记一次 stackoverflowerror 线上排查过程

一.线上 stackOverFlowError xxx日,突然收到线上日志关键字频繁告警 classCastException.从字面上的报警来看,仅仅是类型转换异常,查看细则发现其实是 stackOverFlowError.很多同学面试的时候总会被问到有没有遇到过线上stackOverFlowError?有么有遇到栈溢出?具体栈溢出怎么来…

Javat集合之Lis---(ArrayList和LinkedList)

文章目录 一、 List概述1.1概念1.2list体系结构图1.3 通用方法测试代码 二、List的特点三、遍历方式foreachfor循环迭代器 四、ArrayListArrayList概述概念数据结构 ArrayList的特点 ArrayList去重字符串去重对象去重 五、LinkedListLinkedList概述概念数据结构LinkedList的特点…

FTP网络文件共享服务

ftp的存储类型 1.直连式&#xff1a;距离最近&#xff0c;存储设备爱只连接到服务器上&#xff0c;速度最快&#xff0c;因为不经过网络 2.存储区域网络&#xff08;SAN&#xff09;&#xff1a;适用于大型应用或数据库系统&#xff0c;可以使用空间&#xff0c;也可以管理。…

RK3399平台开发系列讲解(网络篇)什么是Linux路由

🚀返回专栏总目录 文章目录 一、什么是路由二、路由配置命令沉淀、分享、成长,让自己和他人都能有所收获!😄 一、什么是路由 一张路由表中会有多条路由规则。每一条规则至少包含这三项信息。 目的网络:这个包想去哪儿?出口设备:将包从哪个口扔出去?下一跳网关:下一个…

基于springboot+vue的甘肃非物质文化网站(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 研究背景…

VisualSVN Server下载安装和使用方法、服务器搭建、使用TortoiseSvn将项目上传到云端服务器、各种错误解决方法

VisualSVN Server下载安装和使用方法、服务器搭建、使用TortoiseSvn将项目上传到云端服务器、各种错误解决方法 0.写在前面00.电脑配置01.思路 1.VisualSVN Server下载安装01.下载02.安装03.电脑命名不能有中文04.制作VisualSVN Server快捷方式05.License limits exceeded, Som…

使用WAF防御网络上的隐蔽威胁之目录穿越

目录穿越&#xff08;Directory Traversal&#xff09;是一种网络安全攻击手段&#xff0c;也被称为路径穿越。 这种攻击允许攻击者访问存储在Web服务器文件系统上的文件和目录&#xff0c;这些文件和目录原本不应该对用户可见或可访问。 通过利用安全漏洞&#xff0c;攻击者…

yolov5 opencv dnn部署自己的模型

yolov5 opencv dnn部署自己的模型 github开源代码地址使用github源码结合自己导出的onnx模型推理自己的视频推理条件c部署c 推理结果 github开源代码地址 yolov5官网还提供的dnn、tensorrt推理链接本人使用的opencv c github代码,代码作者非本人&#xff0c;也是上面作者推荐的…

Axure RP 9 动态面板

目录 轮播图绘制 多种方式登录 前言: 轮播图绘制、多种方式登录界面绘制 轮播图绘制 首先绘制一个动态面板 在概要区域选中动态面板进入State1面板中插入图片绘制 双击图片绘制插入本地图片&#xff0c;右键State1重复状态并更改图片 点击交互面板新建交互将需要添加…

嵌入式软件工程师面试题——2025校招社招通用(计算机网络篇)(三十二)

说明&#xff1a; 面试群&#xff0c;群号&#xff1a; 228447240面试题来源于网络书籍&#xff0c;公司题目以及博主原创或修改&#xff08;题目大部分来源于各种公司&#xff09;&#xff1b;文中很多题目&#xff0c;或许大家直接编译器写完&#xff0c;1分钟就出结果了。但…

【RT-DETR有效改进】 主干篇 | SwinTransformer替换Backbone(附代码 + 详细修改步骤 +原理介绍)

前言 大家好&#xff0c;这里是RT-DETR有效涨点专栏。 本专栏的内容为根据ultralytics版本的RT-DETR进行改进&#xff0c;内容持续更新&#xff0c;每周更新文章数量3-10篇。 专栏以ResNet18、ResNet50为基础修改版本&#xff0c;同时修改内容也支持ResNet32、ResNet101和PP…

bxCAN 工作模式

bxCAN 工作模式 bxCAN 有三种主要的工作模式&#xff1a;初始化、正常和睡眠。硬件复位后&#xff0c;bxCAN 进入睡眠模式以降低功耗&#xff0c;同时 CANTX 上的内部上拉电阻激活。软件将主控制寄存器&#xff08;CAN_MCR---CAN master control register&#xff09;的初始化…

2024-01-22(MongoDB)

1.Mongodb使用的业务场景&#xff1a; 传统的关系型数据库/mysql在“三高”需求以及应对web2.0的网站需求面前&#xff0c;有点力不从心&#xff0c;什么是“三高”需求&#xff1a; a. 对数据库高并发的读写需求 b. 对海量数据的高效率存储和访问需求 c. 对数据库的高可扩…

二、arcgis 点shp数据处理

在工作中&#xff0c;很多时候客户会提供点坐标&#xff0c;那么要想把点坐标生成shp文件&#xff0c;有两种方法&#xff08;坐标系CGCS2000&#xff09;&#xff1a; 1.当只有个位数的点坐标时&#xff0c;可以直接在arcgisMap中添加&#xff0c;具体步骤如下&#xff1a; …

表达式计算

四则运算表达式可以用表达式树表达&#xff0c;如下图后序遍历 现给你一个字符串&#xff0c;代表一个后序遍历形式的四则运算表达式&#xff0c;请计算出表达式的结果&#xff1a;(只输出整数部分) 注&#xff1a;除法只保留整数部分&#xff1b;5/4 1 输入&#xff1a; 一个…