精华内容
下载资源
问答
  • JAVA类之间方法的调用

    万次阅读 多人点赞 2018-11-02 23:39:15
    JAVA类方法的调用一、静态方法调用其他方法:1. 静态方法调用非静态方法2.静态方法调用静态方法二、非静态方法调用其他方法1.非静态方法在同一类内调用其他方法2.非静态方法在不同类之间调用其他方法 注:调用方法...

    注:调用方法——调用另一方法的方法
    被调用方法——被调用的方法

    一、静态方法调用其他方法:

    1. 静态方法调用非静态方法

    无论是否在同一类内,均需要通过对象调用

    //Test类
    package main;
    
    public class Test {
    
        public void IsSon1(){//非静态方法
            System.out.println("java大爷,你成功调用了你非静态方法里的儿子1");
        }
    
        public static void main(String[] args) {
            Test son1=new Test();
            son1.IsSon1();//静态方法通过对象调用此类中的非静态方法
            Son son=new Son();//静态方法通过对象调用Son类中的非静态方法
            son.IsSon();
        }
    }
    
    //Son类
    package main;
    
    public class Son {
        public  void IsSon(){
            System.out.println("java大爷,你成功的调用了你另一个类里的儿子");
        }//Son类里的非静态方法
    }
    

    输出结果

    2.静态方法调用静态方法

    同一类内直接调用,不同类内直接通过类名.方法名(参数表)调用

    package main;
    
    public class Test {
    
        public static void IsSon2(){//静态方法
            System.out.println("java大爷,你成功调用了你静态方法里的儿子2");
        }
    
        public static void main(String[] args) {
            IsSon2();//静态方法直接调用类内的静态方法
            Son.IsSon3();//静态方法通过类名直接调用Son类中的静态方法
        }
    }
    
    package main;
    
    public class Son {
        public  static void IsSon3(){
            System.out.println("java大爷,你成功的调用了你另一个类里的静态儿子3");
        }//Son类里的静态方法
    }
    
    

    输出结果

    二、非静态方法调用其他方法

    1.非静态方法在同一类内调用其他方法

    在同一类内,非静态方法可以直接调用静态方法和非静态方法

    package main;
    
    public class Test {
    
        public void Son1(){//非静态方法
            System.out.println("java大爷,你成功调用了你非静态方法里的儿子1");
        }
        public static void Son2(){//静态方法
            System.out.println("java大爷,你成功调用了你静态方法里的儿子2");
        }
        public void alloutput(){
            Son1();//非静态方法直接调用类内的非静态方法△
            Son2();//非静态方法直接调用类内的静态方法△
        }
        public static void main(String[] args) {
            Test test = new Test();
            test.alloutput();//前边已学静态方法通过对象调用非静态方法
        }
    }
    

    输出结果

    2.非静态方法在不同类之间调用其他方法

    在不同类之间,非静态方法需要通过对象才能调用非静态方法。
    非静态方法既可以通过对象调用静态方法又可以通过类名直接调用(由于对象的调用方式属于非静态调用方式,所以建议使用类名直接调用静态方法)

    package main;
    
    public class Test {
    
        public void output(){
            Son.IsSon1();//通过类名直接调用Son类中的静态方法,不建议使用对象调用静态方法
            Son son = new Son();
            son.IsSon2();//通过对象调用Son类中的非静态方法
        }
    
        public static void main(String[] args) {
            //同一类中的静态方法调用非静态方法output,前边已经涉及到
            Test test = new Test();
            test.output();
        }
    }
    
    package main;
    
    public class Son {
    
        public  static void IsSon1(){//Son类里的静态方法
            System.out.println("java大爷,你成功的调用了你另一个类里的静态儿子1");
        }
    
        public  void IsSon2(){//Son类里的非静态方法
            System.out.println("java大爷,你成功的调用了你另一个类里的非静态儿子2");
        }
    }
    
    

    输出结果

    借鉴前人的经验1

    借鉴前人的经验2
    小白上路,如有问题希望各路神手指教 /抱拳

    展开全文
  • 我们通过函数调用的方式进行运算,有两种方式得到运算结果 ①设置函数的返回值,return ②将传入值的地址(即传入值自身)交给函数,函数对其进行运算相当于直接对传入值进行运算。 2.输入参数的定义 我们在...

    在matlab里.m文件分执行文件和函数文件
    在c++中执行文件指:main函数
    函数文件:其他所有需要用到的函数

    在c++中,函数文件名没有特殊讲究,将文件添加到工程目录便能使用
    在这里插入图片描述
    对函数的要求有三点

    函数的完整文件
    输入参数的定义
    函数声明加入头文件

    1.函数的完整文件

    #include <opencv2/opencv.hpp>
    using namespace cv;
    
    void cameracapture(Mat &frame, int mytime, int imageWidth,int imageHeight)
    {
    	char c = 0;
    	VideoCapture capture(0);
    	capture.set(CV_CAP_PROP_FRAME_WIDTH, imageWidth*2);//宽度2560
    	capture.set(CV_CAP_PROP_FRAME_HEIGHT, imageHeight);//高度720
    	
    	for (int i=0; i < mytime; i++)
    	{
    		capture >> frame;
    	}
    }
    

    函数的完整文件包括了函数需要的头文件

     #include <opencv2/opencv.hpp>
     using namespace cv;
    

    以及剩下的函数的程序段
    这里解释一下加&和不加&的区别
    Mat &frame 加&的变量传递的是变量地址,直白的理解为,加了后我在函数中对该变量修改后,会对我的主函数main中的对应变量进行修改。这里我的程序是打开相机,并把拍摄图像返回main函数,因此我需要随时根据拍摄修改我的main函数中frame的值。
    int mytime, int imageWidth,int imageHeight这些则是传入值,在函数内进行修改后不影响main里面的值,因为这些值只传入函数,而不需要函数再传回主函数。
    这里还有一点编程技巧
    我们通过函数调用的方式进行运算,有两种方式得到运算结果
    ①设置函数的返回值,return
    ②将传入值的地址(即传入值自身)交给函数,函数对其进行运算相当于直接对传入值进行运算。

    2.输入参数的定义

    我们在main中调用其他函数时,我们的输入参数需要提前定义

    main ()
    {
    Mat frame; 
    int mytime = 10;
    int imageWidth = 1280;
    int imageHeight = 720;
    cameracapture(frame, mytime, imageWidth, imageHeight);//注意这里和函数定义不同
    ………………
    }
    

    3.函数声明加入头文件

    我们调用其他函数前必须先声明

     void cameracapture(Mat &frame, int mytime, int imageWidth,int imageHeight)
    

    写入.h文件(头文件),写入头文件后也就告知了我们的项目,我们声明了,项目中是有该函数的定义的。为什么要用头文件?因为我们把我们用到的函数声明都写到一个.h文件里,下次再使用时我们直接#include XXX.h即可,没有必要再对用到的函数一个一个地声明。

    完成上面的三步,我们自己的函数就制作好了,使用起来比较方便。
    这里再扩展一下
    我们在数组传入函数,传出函数时可能会面临着数组无法修改的问题,这里二郎给大家提供一个解决办法,不是最优,但是可行
    main里面:

    float key_data[10][4] = { 0 };
    my_f(img_cir_L, img_cir_R, key_data);
    

    函数里面:

    void my_f(Mat rectifyImageL, Mat rectifyImageR, float(&key_data)[10][4])
    

    头文件里面:

     void my_f(Mat rectifyImageL, Mat rectifyImageR, float(&key_data)[10][4]);
    

    这样便能实现数组数据的传入和处理后结果的传递了

    展开全文
  • chrome 调用本地exe

    热门讨论 2014-08-18 08:43:45
    1,chrome 浏览器本身不支持直接调用exe,但可以使用url protocol handler 调用exe 2,直接双击exe_chrome.reg 安装注册表 3,test.html 要在运行在容器里(tomcat,resin XXXX),本地直接打开是执行不了的,我...
  • Android中调用js方法及js中调用本地方法,具体请看:http://blog.csdn.net/princelxz/article/details/27666979
  • Java 调用Http Rest接口 例子说明

    热门讨论 2016-07-07 21:50:21
    Java 调用Http Rest接口 例子说明
  • 面试杀手锏之Dubbo服务调用过程

    万次阅读 多人点赞 2020-09-14 08:51:58
    简述一下就是客户端发起调用,实际调用的是代理类,代理类最终调用的是 Client (默认Netty),需要构造好协议头,然后将 Java 的对象序列化生成协议体,然后网络调用传输。 服务端的 NettyServer接到这个请求之后,...

    点赞再看,养成习惯,微信搜一搜【三太子敖丙】关注这个喜欢写情怀的程序员。

    本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点、资料以及我的系列文章。

    前言

    前面我已经带着大家过了服务暴露和服务引入两个流程了,而这两个流程就是为了服务的调用,今天丙就带着大家来过一遍 Dubbo 服务调用流程。

    看完今天的服务调用流程,基本上Dubbo的核心过程就完整的串联起来了,在脑海中应该就有 Dubbo 整体运行的概念,这体系就建立起来了,对 RPC 也会有进一步的认识。

    话不多说,直接进入正题吧!

    简单的想想大致流程

    在分析Dubbo 的服务调用过程前我们先来思考一下如果让我们自己实现的话一次调用过程需要经历哪些步骤?

    首先我们已经知晓了远程服务的地址,然后我们要做的就是把我们要调用的方法具体信息告知远程服务,让远程服务解析这些信息

    然后根据这些信息找到对应的实现类,然后进行调用,调用完了之后再原路返回,然后客户端解析响应再返回即可。

    调用具体的信息

    那客户端告知服务端的具体信息应该包含哪些呢?

    首先客户端肯定要告知要调用是服务端的哪个接口,当然还需要方法名、方法的参数类型、方法的参数值,还有可能存在多个版本的情况,所以还得带上版本号。

    由这么几个参数,那么服务端就可以清晰的得知客户端要调用的是哪个方法,可以进行精确调用!

    然后组装响应返回即可,我这里贴一个实际调用请求对象列子。

    data 就是我所说的那些数据,其他是框架的,包括协议版本、调用方式等等这个下面再分析。

    到此其实大致的意思大家都清楚了,就是普通的远程调用,告知请求的参数,然后服务端解析参数找到对应的实现调用,再返回。

    落地的调用流程

    上面的是想象的调用流程,真实的落地调用流程没有这么简单。

    首先远程调用需要定义协议,也就是互相约定我们要讲什么样的语言,要保证双方都能听得懂。

    比如我会英语和中文,你也会英语、中文,我们之间要做约定,选定一个语言比如都用中文来谈话,有人说不对啊,你中文夹着的英文我也能听得懂啊。

    那是因为你的大脑很智能,它能智能地识别到交流的语言,而计算机可不是,你想想你的代码写 print 1,它还能打出 2 不成?

    也就是计算机是死板的,我们的程序告诉它该怎么做,它就会生硬的怎么做。

    需要一个协议

    所以首先需要双方定义一个协议,这样计算机才能解析出正确的信息

    常见的三种协议形式

    应用层一般有三种类型的协议形式,分别是:固定长度形式、特殊字符隔断形式、header+body 形式。

    固定长度形式:指的是协议的长度是固定的,比如100个字节为一个协议单元,那么读取100个字节之后就开始解析。

    优点就是效率较高,无脑读一定长度就解析。

    缺点就是死板,每次长度只能固定,不能超过限制的长度,并且短了还得填充,在 RPC 场景中不太合适,谁晓得参数啥的要多长,定长了浪费,定短了不够。

    特殊字符隔断形式:其实就是定义一个特殊结束符,根据特殊的结束符来判断一个协议单元的结束,比如用换行符等等。

    这个协议的优点是长度自由,反正根据特殊字符来截断,缺点就是需要一直读,直到读到一个完整的协议单元之后才能开始解析,然后假如传输的数据里面混入了这个特殊字符就出错了。

    header+body 形式:也就是头部是固定长度的,然后头部里面会填写 body 的长度, body 是不固定长度的,这样伸缩性就比较好了,可以先解析头部,然后根据头部得到 body 的 len 然后解析 body。

    dubbo 协议就是属于 header+body 形式,而且也有特殊的字符 0xdabb ,这是用来解决 TCP 网络粘包问题的。

    Dubbo 协议

    Dubbo 支持的协议很多,我们就简单的分析下 Dubbo 协议。

    协议分为协议头和协议体,可以看到 16 字节的头部主要携带了魔法数,也就是之前说的 0xdabb,然后一些请求的设置,消息体的长度等等。

    16 字节之后就是协议体了,包括协议版本、接口名字、接口版本、方法名字等等。

    其实协议很重要,因为从中可以得知很多信息,而且只有懂了协议的内容,才能看得懂编码器和解码器在干嘛,我再截取一张官网对协议的解释图。

    需要约定序列化器

    网络是以字节流的形式传输的,相对于我们的对象来说,我们对象是多维的,而字节流是一维的,我们需要把我们的对象压缩成一维的字节流传输到对端。

    然后对端再反序列化这些字节流变成对象。

    序列化协议

    其实从上图的协议中可以得知 Dubbo 支持很多种序列化,我不具体分析每一种协议,就大致分析序列化的种类,万变不离其宗。

    序列化大致分为两大类,一种是字符型,一种是二进制流。

    字符型的代表就是 XML、JSON,字符型的优点就是调试方便,它是对人友好的,我们一看就能知道那个字段对应的哪个参数。

    缺点就是传输的效率低,有很多冗余的东西,比如 JSON 的括号,对于网络传输来说传输的时间变长,占用的带宽变大。

    还有一大类就是二进制流型,这种类型是对机器友好的,它的数据更加的紧凑,所以占用的字节数更小,传输更快。

    缺点就是调试很难,肉眼是无法识别的,必须借用特殊的工具转换。

    更深层次的就不深入了,序列化还是有很多门道的,以后有机会再谈。

    Dubbo 默认用的是 hessian2 序列化协议。

    所以实际落地还需要先约定好协议,然后再选择好序列化方式构造完请求之后发送。

    粗略的调用流程图

    我们来看一下官网的图。

    简述一下就是客户端发起调用,实际调用的是代理类,代理类最终调用的是 Client (默认Netty),需要构造好协议头,然后将 Java 的对象序列化生成协议体,然后网络调用传输。

    服务端的 NettyServer接到这个请求之后,分发给业务线程池,由业务线程调用具体的实现方法。

    但是这还不够,因为 Dubbo 是一个生产级别的 RPC 框架,它需要更加的安全、稳重。

    详细的调用流程

    前面已经分析过了客户端也是要序列化构造请求的,为了让图更加突出重点,所以就省略了这一步,当然还有响应回来的步骤,暂时就理解为原路返回,下文会再做分析。

    可以看到生产级别就得稳,因此服务端往往会有多个,多个服务端的服务就会有多个 Invoker,最终需要通过路由过滤,然后再通过负载均衡机制来选出一个 Invoker 进行调用。

    当然 Cluster 还有容错机制,包括重试等等。

    请求会先到达 Netty 的 I/O 线程池进行读写和可选的序列化和反序列化,可以通过 decode.in.io控制,然后通过业务线程池处理反序列化之后的对象,找到对应 Invoker 进行调用。

    调用流程-客户端源码分析

    客户端调用一下代码。

    String hello = demoService.sayHello("world"); 
    

    调用具体的接口会调用生成的代理类,而代理类会生成一个 RpcInvocation 对象调用 MockClusterInvoker#invoke方法。

    此时生成的 RpcInvocation 如下图所示,包含方法名、参数类和参数值。

    然后我们再来看一下 MockClusterInvoker#invoke 代码。

    可以看到就是判断配置里面有没有配置 mock, mock 的话就不展开分析了,我们来看看 this.invoker.invoke 的实现,实际上会调用 AbstractClusterInvoker#invoker 。

    模板方法

    这其实就是很常见的设计模式之一,模板方法。如果你经常看源码的话你知道这个设计模式真的是太常见的。

    模板方法其实就是在抽象类中定好代码的执行骨架,然后将具体的实现延迟到子类中,由子类来自定义个性化实现,也就是说可以在不改变整体执行步骤的情况下修改步骤里面的实现,减少了重复的代码,也利于扩展,符合开闭原则。

    在代码中就是那个 doInvoke由子类来实现,上面的一些步骤都是每个子类都要走的,所以抽到抽象类中。

    路由和负载均衡得到 Invoker

    我们再来看那个 list(invocation),其实就是通过方法名找 Invoker,然后服务的路由过滤一波,也有再造一个 MockInvoker 的。

    然后带着这些 Invoker 再进行一波 loadbalance 的挑选,得到一个 Invoker,我们默认使用的是 FailoverClusterInvoker,也就是失败自动切换的容错方式,其实关于路由、集群、负载均衡是独立的模块,如果展开讲的话还是有很多内容的,所以需要另起一篇讲,这篇文章就把它们先作为黑盒使用。

    稍微总结一下就是 FailoverClusterInvoker 拿到 Directory 返回的 Invoker 列表,并且经过路由之后,它会让 LoadBalance 从 Invoker 列表中选择一个 Invoker

    最后FailoverClusterInvoker会将参数传给选择出的那个 Invoker 实例的 invoke 方法,进行真正的远程调用,我们来简单的看下 FailoverClusterInvoker#doInvoke,为了突出重点我删除了很多方法。

    发起调用的这个 invoke 又是调用抽象类中的 invoke 然后再调用子类的 doInvoker,抽象类中的方法很简单我就不展示了,影响不大,直接看子类 DubboInvoker 的 doInvoke 方法。

    调用的三种方式

    从上面的代码可以看到调用一共分为三种,分别是 oneway、异步、同步。

    oneway还是很常见的,就是当你不关心你的请求是否发送成功的情况下,就用 oneway 的方式发送,这种方式消耗最小,啥都不用记,啥都不用管。

    异步调用,其实 Dubbo 天然就是异步的,可以看到 client 发送请求之后会得到一个 ResponseFuture,然后把 future 包装一下塞到上下文中,这样用户就可以从上下文中拿到这个 future,然后用户可以做了一波操作之后再调用 future.get 等待结果。

    同步调用,这是我们最常用的,也就是 Dubbo 框架帮助我们异步转同步了,从代码可以看到在 Dubbo 源码中就调用了 future.get,所以给用户的感觉就是我调用了这个接口的方法之后就阻塞住了,必须要等待结果到了之后才能返回,所以就是同步的。

    可以看到 Dubbo 本质上就是异步的,为什么有同步就是因为框架帮我们转了一下,而同步和异步的区别其实就是future.get 在用户代码被调用还是在框架代码被调用

    再回到源码中来,currentClient.request 源码如下就是组装 request 然后构造一个 future 然后调用 NettyClient 发送请求。

    我们再来看一下 DefaultFuture 的内部,你有没有想过一个问题,因为是异步,那么这个 future 保存了之后,等响应回来了如何找到对应的 future 呢?

    这里就揭秘了!就是利用一个唯一 ID。

    可以看到 Request 会生成一个全局唯一 ID,然后 future 内部会将自己和 ID 存储到一个 ConcurrentHashMap。这个 ID 发送到服务端之后,服务端也会把这个 ID 返回来,这样通过这个 ID 再去ConcurrentHashMap 里面就可以找到对应的 future ,这样整个连接就正确且完整了!

    我们再来看看最终接受到响应的代码,应该就很清晰了。

    先看下一个响应的 message 的样子:

    Response [id=14, version=null, status=20, event=false, error=null, result=RpcResult [result=Hello world, response from provider: 192.168.1.17:20881, exception=null]]
    

    看到这个 ID 了吧,最终会调用 DefaultFuture#received的方法。

    为了能让大家更加的清晰,我再画个图:

    到这里差不多客户端调用主流程已经很清晰了,其实还有很多细节,之后的文章再讲述,不然一下太乱太杂了。

    发起请求的调用链如下图所示:

    处理请求响应的调用链如下图所示:

    调用流程-服务端端源码分析

    服务端接收到请求之后就会解析请求得到消息,这消息又有五种派发策略:

    默认走的是 all,也就是所有消息都派发到业务线程池中,我们来看下 AllChannelHandler 的实现。

    就是将消息封装成一个 ChannelEventRunnable 扔到业务线程池中执行,ChannelEventRunnable 里面会根据 ChannelState 调用对于的处理方法,这里是 ChannelState.RECEIVED,所以调用 handler.received,最终会调用 HeaderExchangeHandler#handleRequest,我们就来看下这个代码。

    这波关键点看到了吧,构造的响应先塞入请求的 ID,我们再来看看这个 reply 干了啥。

    最后的调用我们已经清楚了,实际上会调用一个 Javassist 生成的代理类,里面包含了真正的实现类,之前已经分析过了这里就不再深入了,我们再来看看getInvoker 这个方法,看看怎么根据请求的信息找到对应的 invoker 的。

    关键就是那个 serviceKey, 还记得之前服务暴露将invoker 封装成 exporter 之后再构建了一个 serviceKey将其和 exporter 存入了 exporterMap 中吧,这 map 这个时候就起作用了!

    这个 Key 就长这样:

    找到 invoker 最终调用实现类具体的方法再返回响应整个流程就完结了,我再补充一下之前的图。

    总结

    今天的调用过程我再总结一遍应该差不多了。

    首先客户端调用接口的某个方法,实际调用的是代理类,代理类会通过 cluster 从 directory 中获取一堆 invokers(如果有一堆的话),然后进行 router 的过滤(其中看配置也会添加 mockInvoker 用于服务降级),然后再通过 SPI 得到 loadBalance 进行一波负载均衡。

    这里要强调一下默认的 cluster 是 FailoverCluster ,会进行容错重试处理,这个日后再详细分析。

    现在我们已经得到要调用的远程服务对应的 invoker 了,此时根据具体的协议构造请求头,然后将参数根据具体的序列化协议序列化之后构造塞入请求体中,再通过 NettyClient 发起远程调用。

    服务端 NettyServer 收到请求之后,根据协议得到信息并且反序列化成对象,再按照派发策略派发消息,默认是 All,扔给业务线程池。

    业务线程会根据消息类型判断然后得到 serviceKey 从之前服务暴露生成的 exporterMap 中得到对应的 Invoker ,然后调用真实的实现类。

    最终将结果返回,因为请求和响应都有一个统一的 ID, 客户端根据响应的 ID 找到存储起来的 Future, 然后塞入响应再唤醒等待 future 的线程,完成一次远程调用全过程。

    而且还小谈了下模板方法这个设计模式,当然其实隐藏了很多设计模式在其中,比如责任链、装饰器等等,没有特意挑开来说,源码中太常见了,基本上无处不在。

    絮叨

    经过的今天的文章相信大家对 RPC 调用也有了进一步的认识,之前的服务暴露和服务引入都是为了完成远程调用。

    对于编解码那一块我只是说了下具体的协议,没有从源码的角度分析因为那部分的代码其实就是按照协议的编写和获取的,比较的死板,有兴趣的同学可以自行研究,有些关于 Buffer 的操作还是需要一定的基础的。

    主线基本上都讲完了,但是还有路由、集群等机制没有详细的分析,这部分也是很重要的,比较生产环境基本上都是集群部署,没有愣头青是单上的,所以 Dubbo 对这方面的支持也是很重要的,日后再分析。

    絮叨

    另外,敖丙把自己的面试文章整理成了一本电子书,共 1630页!目录如下,还有我复习时总结的面试题以及简历模板,现在免费送给大家。

    链接:https://pan.baidu.com/s/1ZQEKJBgtYle3v-1LimcSwg 密码:wjk6

    我是敖丙,你知道的越多,你不知道的越多,感谢各位人才的:点赞收藏评论,我们下期见!


    文章持续更新,可以微信搜一搜「 三太子敖丙 」第一时间阅读,回复【资料】有我准备的一线大厂面试资料和简历模板,本文 GitHub https://github.com/JavaFamily 已经收录,有大厂面试完整考点,欢迎Star。

    展开全文
  • C#调用java直接调用无需生成.net组件

    热门讨论 2013-08-28 22:20:53
    C#调用java,可以直接调用.jar和.class文件,无需生成.net组件,更稳定快速
  • 自动生成函数调用关系图

    热门讨论 2013-09-06 20:21:17
    自动生成c++函数调用关系图,里面包含了所有要用到的软件,一站式服务; 通过本人亲测的使用总结; 还有使用到的配置文件(c++的),实在不会配置可以直接使用; 改一改配置文件,应该还可以生成c,java,c#语言的调用...
  • QT编写DLL给外部程序调用示例 方法 参数 返回值 事件回调 : 1:C#或者 NET 第一步:引入命名空间; using System Runtime InteropServices; 第二步:声明函数 必须与实际DLL中函数名及参数一致; [DllImport "qt...
  • Java调用Python的jar包

    热门讨论 2015-10-30 14:14:09
    Java调用Python的jar包,使用java调用python的时候jar包,不好找!
  • qt调用zlib实例

    热门讨论 2014-08-15 14:52:01
    qt调用zlib实例
  • html5手机网站调用微信分享

    千次下载 热门讨论 2015-07-16 14:23:26
    html5手机网站调用微信分享,其中示例包括 1. 获取网络类型 2. 调起客户端的图片播放组件 3. 调用微信扫描二维码 4. 判断是否安装对应的应用 5. 发送邮件 6. 分享到微信朋友圈
  • C++调用百度地图API

    热门讨论 2015-05-11 09:16:17
    通过C++代码调用百度地图API,一个简单实用的百度地图操作实例,希望能给大家带来帮助。
  • java调用webservice的demo

    千次下载 热门讨论 2015-04-03 15:49:23
    java调用web service的完整源码。可以使用。
  • 安卓webview中h5页面里的js和java相互调用,js和Android代码相互调用
  • Android 调用系统相机拍照、以及相册

    千次下载 热门讨论 2015-04-11 19:54:37
    Android 调用系统相机拍照、以及相册。完成之后图片是上传到app上。没有上传到服务器,因为我没服务器测试。但项目里面有个类可以参考上传图片到服务器,我就没测试了。欢迎下载。
  • java用JNA调用dll实例,包含各种参数调用

    千次下载 热门讨论 2013-04-17 18:40:54
    实例中演示了各种参数形式的DLL函数调用,如:基本数据类型、基本数据类型的指针和引用、结构体、结构体的指针和引用、函数指针和回调函数、字符串指针、输入数组、输出数组等,非常实用。
  • 系统调用的概念及原理

    千次阅读 多人点赞 2019-10-31 16:48:30
    系统调用与内核函数 内核函数与普通函数形式上没有什么区别,只不过前者在内核实现,因此要满足一些内核编程的要求。 系统调用是用户进程进入内核的接口层,它本身并非内核函数,但它是由内核函数实现的,进入内核...

    系统调用与内核函数

    内核函数与普通函数形式上没有什么区别,只不过前者在内核实现,因此要满足一些内核编程的要求。
    系统调用是用户进程进入内核的接口层,它本身并非内核函数,但它是由内核函数实现的,进入内核后,不同的系统调用会找到相应的内核函数,这些内核函数被称为系统调用的“服务例程”。
    比如系统调用getpid()实际调用的是服务例程sys_getpid(),也可以说,系统调用getpid()是服务例程sys_getpid()的“封装例程”。

    系统调用基本概念

    计算机的各种硬件资源是有限的,为了更好的管理这些资源,用户进程是不允许直接操作的,所有对这些资源的访问都必须由操作系统控制。为此操作系统为用户态运行的进程与硬件设备之间进行交互提供了一组接口,这组接口就是所谓的系统调用。

    那么在应用程序和硬件之间设置这样一个接口层有什么优点呢?
    1. 把用户从学习硬件设备的低级编程特性中解放出来。
    2. 提高了系统的安全性,内核在满足某个请求之前就可以在接口级检查这个请求的正确性。
    3. 最重要的是,这些接口使得程序更具有可移植性,因为只要不同操作系统所提供的一组接口相同,那么在这些操作
    系统上就可以正确的编译和执行相同的程序。
    

    系统调用实质上就是函数调用,只不过调用的是系统函数,处于内核态而已。 用户在调用系统调用时会向内核传递一个系统调用号,然后系统调用处理程序通过此号从系统调用表中找到相应的内核函数执行,最后返回。

    系统调用号

    Linux系统有几百个系统调用,为了唯一的标识每一个系统调用,Linux为每一个系统调用定义了一个唯一的编号,这个编号就是系统调用号。(在我的电脑上,它是在 /usr/include/x86_64-linux-gnu/asm/unistd_32.h, 可以通过 find / -name unistd_32.h -print 查找)。
    在这里插入图片描述
    系统调用号的另一个目的是作为系统调用表的下标,当用户空间的进程执行一个系统调用的时侯,这个系统调用号就被用来指明到底是要执行那个系统调用。

    系统调用表

    为了把系统调用号与相应的服务例程关联起来,内核利用了一个系统调用表,存放在sys_call_table数组中,它是一个函数指针数组,每一个函数指针都指向其系统调用的封装例程,有NR_syscalls个表项,第n个表项包含系统调用号为n的服务例程的地址。

    系统调用处理函数

    系统调用最终还是会由内核函数完成,那么为什么不直接调用内核函数呢?
    这是因为用户空间的程序无法直接执行内核代码,因为内核驻留在受保护的地址空间上,不允许用户进程在内核地址空间上读写。所以,应用程序会以某种方式通知系统,告诉内核需要执行一个函数调用,这种通知机制是靠软中断来实现的,通过引发一个异常来促使系统切换到内核态去执行异常处理程序。此时的异常处理程序就是所谓的系统调用处理程序。

    系统调用是属于操作系统内核的一部分,必须以某种方式提供给进程让它们去调用。CPU可以在不同的特权级别下运行,
    而相应的操作系统也有不同的运行级别,用户态和内核态。运行在内核态的进程可以毫无限制的访问各种资源,
    而在用户态下的用户进程的各种操作都有着限制,比如不能随意的访问内存、不能开闭中断以及切换运行的特权级别。
    所以操作系统通过中断从用户态切换到内核态。
    

    补充——中断是什么

    中断控制是计算机发展中一种重要的技术。 最初它是为克服对I/O接口控制采用程序查询所带来的处理器效率低而产生的。
    中断控制的主要优点是只有在I/O需要服务时才能得到处理器的响应,而不需要处理器不断地进行查询。
    由此,最初的中断全部是对外部设备而言的,称为外部中断(或硬件中断)。
    但随着计算机系统结构的不断改进以及应用技术的日益提高,中断的适用范围也随之扩大,出现了所谓的内部中断(或叫异常),
    它是为解决机器运行时所出现的某些随机事件及编程方便而出现的。因而形成了一个完整的中断系统。
    

    中断可分为两大类:异常中断
    异常分为故障陷阱特点是既不使用中断控制器,也不能被屏蔽(异常实际上是CPU发出的中断信号)。
    中断分为外部可屏蔽中断和外部非屏蔽中断,所有I/O设备产生的中断请求均引起屏蔽中断,而紧急事件(如硬件故障)引起的故障产生非屏蔽中断。

    Intel x86系列微机共支持256中向量中断,Linux对256个向量的分配如下:
    (1) 从0~31的向量对应异常和非屏蔽中断。
    (2) 从32~47的向量分配给屏蔽中断。
    (3) 从48~255的向量用来标识软中断。Linux只用了其中一个(128向量即0x80向量)用来实现系统调用。
    注:Linux为什么只使用一个中断号来对应所有的系统调用,而不是一个中断号对应一个系统调用?
    因为中断号是有限的,而系统调用又太多了。

    Linux对系统调用的调用必须通过执行int $0x80汇编指令,这条指令会产生向量为128的编程异常。
    

    中断有两个重要的属性,中断号中断处理程序。中断号用来标识不同的中断,不同的中断具有不同的中断处理程序。在操作系统内核中维护着一个中断向量表,这个数组存储了所有中断处理程序的地址,而中断号就是相应中断在中断向量表中的偏移量。

    在实地址模式中,CPU把内存中从0开始的1KB用来存储中断向量表。表中的每个表项占4个字节,
    由两个字节的段地址和两个字节的偏移量组成,这样构成的地址便是相应的中断处理程序的入口地址。
    但是,在保护模式下,由4字节的表项构成的中断向量表显然满足不了要求。这是因为:
    <1>除了两个字节的段描述符,偏移量必须用4字节来表示;
    <2>要有反映模式切换的信息。
    因此,在保护模式下,中断向量表中的表项由8个字节组成,中断向量表也改叫做中断描述符表
    IDT(Interrupt Descriptor Table)。其中的每个表项叫做一个门描述符(Gate Descriptor),
    “门”的含义是当中断发生时必须先通过这些门,然后才能进人相应的处理程序。
    

    Linux下系统调用原理

    根据上文,我们知道Linux使用一个中断号来对应所有的系统调用,那么只有一个中断号,操作系统怎么知道是哪一个系统调用要被调用呢?
    上文也提到过,系统调用拥有自己的系统调用号,系统调用表以及系统调用处理函数。一个调用号对应一个处理函数,通过处理函数和调用号在调用表中找到相应的系统调用。

    在Linux中,EAX寄存器是负责传递系统调用号的。
    以fork()为例,fork()的系统调用号为2,在执行int $0x80指令前,调用号会被存放在eax寄存器中,系统调用处理函数(中断处理函数)最终会通过系统调用号,调用正确的系统调用。

    伪代码:
    movl eax,2
    int 0x80
    

    在这里插入图片描述系统调用除了需要传递系统调用号以外,还是需要传递参数,并且具有返回值的,那么参数是怎么传递的呢?
    对于参数传递,Linux也是通过寄存器完成的。Linux最多允许向系统调用传递6个参数,
    分别依次由%ebx,%ecx,%edx,%esi,%edi和%ebp这个6个寄存器完成。

    以调用exit(1)为例

    伪代码:
    movl eax,2
    movl ebx,1
    int 0x80
    

    因为exit需要一个参数1,所以这里只需要使用ebx。这6个寄存器可能已经被使用,所以在传参前必须把当前寄存器的状态保存下来,待系统调用返回后再恢复。

    Linux中,在用户态和内核态运行的进程使用的栈是不同的,分别叫做用户栈和内核栈, 两者各自负责相应特权级别状态下的函数调用。当进行系统调用时,进程不仅要从用户态切换到内核态,同时也要完成栈切换, 这样处于内核态的系统调用才能在内核栈上完成调用。系统调用返回时,还要切换回用户栈,继续完成用户态下的函数调用。

    寄存器%esp(栈指针,指向栈顶)所在的内存空间叫做当前栈, 比如%esp在用户空间则当前栈就是用户栈,否则是内核栈。栈切换主要就是%esp在用户空间和内核空间间的来回赋值。 在Linux中,每个进程都有一个私有的内核栈,当从用户栈切换到内核栈时,需完成保存%esp以及相关寄存器的值(%ebx,%ecx…)并将%esp设置成内核栈的相应值。而从内核栈切换会用户栈时,需要恢复用户栈的%esp及相关寄存器的值以及保存内核栈的信息。

    之前总是听说系统调用很费时,在学习了系统调用的原理后,我们应该也知道了其中的原因

    1. 系统调用通过中断实现,需要从用户态切换到内核态,也就是要完成栈切换。
    2. 会使用寄存器传参,需要额外的保存和恢复的过程。

    以上关于系统调用的总结,都是本人从书本以及网上的资料,博客学习到的,如果由什么不对的地方,欢迎指正。

    展开全文
  • HTML5调用本地摄像头拍照

    千次下载 热门讨论 2014-11-18 09:08:51
    兼容各大主浏览器,要部署在服务器上才可以调用到摄像头
  • 系统调用

    万次阅读 多人点赞 2019-03-02 17:47:48
    程序接口通常是由各种类型的系统调用所组成的,因而,也可以说,系统调用提供了用户程序和操作系统之间的接口,应用程序通过系统调用实现其与 OS 的通信,并可取得它的服务。 处理器(CPU)=运算器+控制器+...
  • js调用本地摄像头拍照并上传到web服务器。后台使用java实现图片的接收和存储,上传的图片默认保存到项目下的images文件夹中。
  • HTML5调用手机摄像头拍照

    千次下载 热门讨论 2014-04-01 14:58:51
    HTML5 The Media Capture API提供了对摄像头的可编程访问,用户可以直接用getUserMedia获得摄像头提供的视频流。具体内容参考: http://blog.sina.com.cn/s/blog_4ad7c2540101lnak.html
  • android JNI C 调用Java

    热门讨论 2012-12-10 15:03:18
    android JNI C 调用Java
  • android调用二维码扫描功能

    热门讨论 2014-05-13 17:00:44
    android下二维码的扫描解析.精简版,通俗易懂
  • html5调用本地摄像头

    热门讨论 2013-05-03 21:07:37
    这是2个用html5调用摄像头的例子,只需要把内容上传到任意服务器上,测试就可以了,因为对于html5本地调用不可用,也就是说直接将txt改成htm是不可用的,可以将其发布到tomcat上,这样就可以了
  • Qt一步一步实现插件调用源码

    热门讨论 2013-12-04 09:13:53
    在linux系统和window系统都能成功编译通过如何进行插件开发
  • 什么是系统调用? Linux内核中设置了一组用于实现各种系统功能的子程序,称为系统调用。用户可以通过系统调用命令在自己的应用程序中调用它们。从某种角度来看,系统调用和普通的函数调用非常相似。区别仅仅在于,...
  • C语言函数调用

    千次阅读 多人点赞 2019-04-30 14:50:25
    C函数调用 调用格式: 函数名(实参表) 并且应该避免写出与实际参数计算次序有关的调用。 函数调用可以出现在以下两种情况中: 无返回值的函数通常作为表达式语句,即直接在函数调用的后面加一个分号; 有返回值的...
  • VC++调用大漠插件

    热门讨论 2013-05-06 18:18:18
    VC++调用大漠插件的实例,多线程调用
  • C++调用C#的DLL实例程序

    热门讨论 2012-08-20 20:21:21
    C++调用C#的DLL实例程序,压缩包中包含部分程序说明,很小的几行代码,但是C++调用C#的DLL目的已经达到。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 9,056,609
精华内容 3,622,643
关键字:

调用