Java—RPC:远程过程调用(1)

2023-11-06

Java—RPC:远程过程调用(1)

在我们学习RPC的过程中,首先我们先认识一下项目结构在发展中干的变化

一、项目结构变化

1、单体结构

​ 单体结构又叫单一项目,在我们所认识的传统项目基本上都是单一项目,j可是在互联网逐步发展的过程中,逐渐的淘汰 。单一项目的架构过于简单,改一个东西都要重新的启动,重新编译。

​ 在单体架构项目中,团队都是通过包进行区分每个模块。

优点:

​ 部署简单、维护方便、开发成本低

缺点:

​ 当项目规模过大,用户的访问量频率高,并发量大;数据量大,会大大的降低执行效率,甚至会出现宕机。

适用项目:

​ 传统管理项目、小型互联网项目。

2.分布式架构

​ 分布式架构就是将一个项目按照特定的情况和要求(或者按照模块和功能)拆分成若干个项目,把每一个项目分别的部署到不同的服务器中。

优点:

​ 增了系统可用性、增加了重用性、增加了可扩展性、增加每个模块的负载能力。

缺点:

​ 成本高、架构更加复杂、整体响应时间变长、吞吐量更大。吞吐量=请求数/秒

适用项目:

​ 中、大型互联网项目。客户多、数据多、并高发、压力大,吞吐量高的项目。

​ 通过以上的项目结构的分析,我们可以很清楚的看出每个项目结构的优缺点,在项目选择上可以更加清楚的做出选择。

​ 通过分布式架构的简介我们可以看出的是:分布式架构中的各个模块是如何进行通信?

​ 在现阶段中我们可以使用Http协议,也可以使用RPC协议通信,也可以使用其他的通信方式,在这里我们着重的介绍使用RPC协议,因为它比Http协议更适合内部通信。

二、RPC简介

​ 2.1、RFC:互联网工程任务组(IEIF)发布的文件集,每一个文件集都有自己唯一的编号,其中我们所介绍的RPC就收集在rfc 1831中。 可以通过下面的网址查看:

​ https://datatracker.ietf.org/doc/rfc1831/

​ 2.2、RPC:协议规定允许互联网中一台主机程序调用另一台主机程序,而程序员无需对这个交互过程进行编程。在RPC协议中强调的是:当X程序调用Y程序的 更能或方法时,X是不知道同时也不需要知道Y中方法具体的实现。

​ RPC是上层协议,但是它的底层是基于TCP协议,也可以基于HTTP协议。一般我们说RPC都是基于RPC的具体实现。

​ RPC框架一般都带有丰富事务服务治理功能,更加的适合企业内部接口调用。而HTTP协议更适合多平台之间相互调用。

​ 在这里我们借用HttpClient来实现RPC协议。HttpClient起初是Apache Jakarta Common 的子项目。是用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持最新的HTTP版本。到2007年的时候已经成为了顶级项目。

下面我们就HttpClient来简单的实现RPC从协议:

首先第一步就是创建一个项目以便我们进行测试:

在这里插入图片描述

第二步导依赖:

<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.3.2.RELEASE</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

第三步书写代码:

3.1:创建一个启动类:
package com.bjsxt.httpclicentserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @SpringBootApplication:是一个组合注解,用于快捷配置启动类
 *
 * 此注解等同于@Configuration+@EnableAutoConfiguration+@ComponentScan的合集
 */
@SpringBootApplication
public class ServerApp {
    public static void main(String[] args) {
        SpringApplication.run(ServerApp.class,args);
    }
}
/*
@SpringBootApplication:是一个组合注解,用于快捷的培训hi启动类可配置多个启动类,但启动时需要选择以那个类作为启动类来启动项目
*/
3.2:创建一个控制类:
package com.bjsxt.httpclicentserver.controller;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class TestController {

    @RequestMapping(value="/test" ,produces={"application/json;charset=UTF-8"})
    @ResponseBody
    public  String test(){
        return "{\"msg\":\"处理返回\"}";
    }
}
/*
@Controller注解:是Spring框架提供的注解,Controller标识类,该类代表控制器(控制层/表现层)。
@RequestMapping注解:是一个用来处理请求地址映射的注解,可以用于类或方法上。用在类上表示类中所有请求的方法都是以该地址作为父路径。
    value属性:指定请求的实际地址
    method属性:指定请求方式,get\post
    consumes属性:指定处理请求的提交内容类型
    produces属性:指定返回内容类型,可以防止中文乱码
	params属性:指定request中必须包含某些参数值时,才让该方法处理
	headers属性:指定request中必须包含某些指定的header值
 @ResponseBody注解:就是将返回的对象通过MessageConverter处理之后,写入response的outputStream中返回。
*/
3.3:测试代码

以上的代码完成后,我们需要通过启动类进行测试返回的结果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E4NsmY5h-1596204049432)(D:\桌面文件\RPC\05.png)]

现在我们暂时是用浏览器进行访问,将来我们就需要用代码进行访问

3.4:创建一个客户端

httpclient_rpc_client

在这里插入图片描述

3.4.1:导入httpClient依赖
<dependencies>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.12</version>
        </dependency>
    </dependencies>

在我们拥有了这个代码以后我们就可以尝试的写客户端代码了

3.4.2:GET无参数客户端代码
package com.bjsxt.httpclient;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.IOException;

/**
 *使用Main方法,测试HttpClient技术
 */
public class TestHttpClient {
    public static void main(String[] args) throws IOException {
        //调用无参数GET请求
        testGetNoParams();
    }
/**
 *在这里我们创建一个静态的没有返回值的类
 * 无参数GET请求
 * 在我们用HttpClient发送请求的时候我们回忆一下
 * 使用浏览器访问网站的过程
 * 1、打开浏览器
 * 2、输入网址
 * 3、访问
 * 4、看结果
 * 使用HttpClient,访问WEB服务器的过程
 * 1、创建客户端,相当于打开浏览器
 * 2、创建请求地址,相当于输入网址
 * 3、发送请求,相当于访问王网址(回车键)
 * 4、返回处理结果,相当于浏览器返回结果
 *通过以上的对比我们可以看出两者之间的相似的程度
 */
    public static void testGetNoParams() throws IOException {
        /*
        注意的是不要导错包了,我们所导入的是
        import org.apache.http.client.HttpClient;包下的HttpClient
         */
        //创建客户端对象
        HttpClient  client = HttpClients.createDefault();

        /*
        创建请求地址
        我们所请求的地址是以字符串形式展现的
        IP:localhost
        端口号:8080
        请求路径:test
         */
        HttpGet get = new HttpGet("http://localhost:8080/test");
        //发起请求,接收响应对象
        HttpResponse response = client.execute(get);
        /*
        获取响应体。响应数据是一个基于HTTP协议标准字符串封装的对象
        响应体和响应头,都是封装的HTTP协议数据。直接使用可能会出现乱码或解析错误.
        所以我们要对数据进行转换。
         */
        HttpEntity entity = response.getEntity();

        /*
        通过HTTP实体类工具,转换响应体数据,使用的字符集是UTF-8
        UTF-8,也可以省略不写,因为默认的就是UTF-8字符集
         */
        String responseString = EntityUtils.toString(entity, "UTF-8");

        System.out.println("服务器响应的结果是-[" + responseString +"]");

        //回收资源
        client = null;
    }
}

3.4.3:返回结果

服务器响应的结果是-[{"msg":"处理返回"}]

Process finished with exit code 0

以上的代码是我们运用的是无参数的请求方式。

3.5:有参数的客户端代码

3.5.1:首先到控制器中增加一个有参数的控制类
 @RequestMapping(value="/params",produces = "application/json;charset=UTF-8")
    @ResponseBody
    public String params(String name,String password){
        System.out.println("name - "+name +";password -" +password);
        return "{\"msg\":\"登录成功\",\"user\"{\"name\":\""+name+"\";\"password\":\""+password+"\"}}";
    }

有参数的控制器写完之后,重新启动一下启动类。

3.5.2:GET有参数客户端代码
//调用有参数GET请求
        testGetParams();
    }

    /*
    有参数的GET请求
     */
    public static void testGetParams() throws URISyntaxException, IOException {
        //创建客户端对象
        HttpClient client = HttpClients.createDefault();

        //基于Builder构建请求地址,有异常直接抛出
        URIBuilder builder = new URIBuilder("http://localhost:8080/params");

        /*//基于单参数传递,构建请求地址
        builder.addParameter("name","bjsxt");
        builder.addParameter("password","123456");
        URI uri= builder.build();*/

        /*基于多参数传递,构建请求地址
        在导入NameValuePair的时候需要注意不要导错包了
        我们所导入的是一个接口在http下:import org.apache.http.NameValuePair;
        NameValuePair是一个接口,自己构建的话直接return返回字符串就行。
        也可以使用BasicNameValuePair,BasicNameValuePair是NameValuePair接口的实现类,
        可以直接new对象,也可以直接传name和value

        或者直接在http请求地址的后面直接加上?
         */
        List<NameValuePair> nvps = new ArrayList<>();
        nvps.add(new BasicNameValuePair("name","bjsxt"));
        nvps.add(new BasicNameValuePair("password","123456"));
        builder.addParameters(nvps);
        URI uri = builder.build();
        System.out.println(uri.toASCIIString());

        /*
        在无参数中我们分开请求的,在这里我们是一起进行处理的。
         */
        String result = EntityUtils.toString(client.execute(new HttpGet(uri)).getEntity());
        System.out.println(result);
    }

3.5.3:返回的结果

http://localhost:8080/params?name=bjsxt&password=123456
{"msg":"登录成功""user"{"name":"bjsxt";"password":"123456"}}

Process finished with exit code

上面的代码操作的都是GET请求的数据,下面我么们开始介绍POST请求

3.6:POST无参数客户端代码

post请求和get请求唯一的区别就是在于我们请求的对象,其它的区别上不大。

public static void testPost() throws IOException {
        //创建客户端对象
        HttpClient client = HttpClients.createDefault();

        /*
        无参的post请求,test对应的是无参的请求
        与get请求唯一的区别就是这里用的是HttpPost
         */
        HttpPost post = new HttpPost("http://localhost:8080/test");
        /*
        有异常直接抛出
         */
        HttpResponse response = client.execute(post);
        System.out.println(EntityUtils.toString(response.getEntity(),"UTF-8"));
    }

3.6:POST有参数的客户端代码:

/*
        有参数的post请求。请求头携带参数。和get请求携带的参数的方式一致
       有异常直接抛出,咱们的对象不用重新创建,就像浏览器页面一样,不需要关了在启动。
       在这里还可以在请求的地址后面加上?参数&参数
         */
        URIBuilder builder = new URIBuilder("http://localhost:8080/params");
        builder.addParameter("name","post");
        builder.addParameter("password","post123456");
        HttpResponse postResponse = client.execute(new HttpPost(builder.build()));
        System.out.println(EntityUtils.toString(postResponse.getEntity(),"UTF-8"));

        /*
        请求体传递参数
        在我们使用post请求的时候,我们一般都是使用请求体进行传参,在非专业人事的眼中是隐藏路径的
         */
        HttpPost bodyParamsPost = new HttpPost("http://localhost:8080/params");

        /*
        定义请求协议体,设置请求参数,这是传字符串形式
        使用请求体传递参数的时候。需要定义请求格式,默认的是表单格式,
        通常我们都会把默认的请求格式进行修改成阶层格式
        使用URIbuilder构建的URI对象,就是请求体传递参数
         */
        HttpEntity entity = new StringEntity("name=bjsxt&password=123");

        /*
        给响应体是同一个类型,它所代表的就是协议体,当两个子类型分别是响应协议体和请求协议体
        面向父类的方式进行开发的
         */
        bodyParamsPost.setEntity(entity);

        //输出
        System.out.println(EntityUtils.toString(client.execute(bodyParamsPost).getEntity(),"UTFa-8"));


    }
返回结果
{"msg":"处理返回"}
{"msg":"登录成功""user"{"name":"post";"password":"post123456"}}
{"msg":"登录成功""user"{"name":"null";"password":"null"}}

Process finished with exit code 0
其中第三的参数属于没有传过来,原因是请求体格式不符合标准要求。这种的请求方式对应的是另一种格式。

3.7:解决参数为空

3.7.1在控制器类增加一个控制类
 //使用请请求体传递请求参数
 @RequestMapping( value = "/bodyParams",produces ="application/json;charset=UTF-8")
    @ResponseBody
    @CrossOrigin
//在这里我先传入了实体类User,这个实体类应该在实体类创建完毕后再传入的。注意一下。
    public String bodyParams(@RequestBody List<User> users){
        System.out.println(users);
        return users.toString();
    }
/*
 @CrossOrigin注解:是用来处理跨域请求的注解
 @RequestBody注解:作用其实是将json格式的数据转为java对象
*/

​ 在这里导入包的时候请注意包是不是导入错误,在这里我们应该导入的是自己的User,而不是导入catalina的User。这样的话会报一个错误:

控制台报的错误:

{"timestamp":"2020-07-31T12:29:27.686+00:00","status":500,"error":"Internal Server Error","message":"","path":"/bodyParams"}

服务器日志:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `org.apache.catalina.User` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
 com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `org.apache.catalina.User` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information

3.7.2:创建一个实体类项目

在这里插入图片描述

3.7.3:在实体类项目中书写实体类的代码
package com.bjsxt.httpclient;

import java.io.Serializable;
import java.util.Objects;

public class User implements Serializable {
    private String name;
    private String password;

    public User() {
    }

    public User(String name, String password) {
        this.name = name;
        this.password = password;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(name, user.name) &&
                Objects.equals(password, user.password);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, password);
    }

    /*
    在这里我把toString代码进行了修改
    */
    @Override
    public String toString() {
        return "{\"name\":\""+name+"\", \"password\":\""+password+"\"}";
    }
}

3.7.4:实体类结束之后需要在另外的两个项目中分别增加依赖
	   <dependency>
            <groupId>org.example</groupId>
            <artifactId>httpclient_rpc_pojo</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

书写完毕后重启一下项目。

再做请求的时候我们就会拿请求体传递数据了。

3.7.5:这样的话我们下面就需要做一些代码上的修改,修改如下,暂时有bug还为解决,已解决。

原因:

​ 控制类导包错误,上面已有解释造成的原因。

/*
        请求体传递参数
        在我们使用post请求的时候,我们一般都是使用请求体进行传参,在非专业人事的眼中是隐藏路径的
         */
        HttpPost bodyParamsPost = new HttpPost("http://localhost:8080/bodyParams");

        /*
        定义请求协议体,设置请求参数,这是传字符串形式
        使用请求体传递参数的时候。需要定义请求格式,默认的是表单格式,
        通常我们都会把默认的请求格式进行修改成阶层格式
        使用URIbuilder构建的URI对象,就是请求体传递参数
         */
        User u1 = new User();
        u1.setName("name1");
        u1.setPassword("password1");
        User u2 = new User();
        u2.setName("name2");
        u2.setPassword("password2");

        /*这是一个集合的表达形式json格式字符串,表示请求参数,一个List<User>
        但是这里面的toString方法不能直接用,这里是我修=修改过的toString方法。
         */
        String paramsString = "["+u1.toString()+","+u2.toString()+"]";
        /*
        StringEntity除了可以传字符串(String)、字符集(Charset)和请求体的格式(mimType)
         */
        HttpEntity entity = new StringEntity(paramsString,"application/json","UTF-8");

        /*
        给响应体是同一个类型,它所代表的就是协议体,当两个子类型分别是响应协议体和请求协议体
        面向父类的方式进行开发的
         */
        bodyParamsPost.setEntity(entity);

        //输出
        System.out.println(EntityUtils.toString(client.execute(bodyParamsPost).getEntity(),"UTF-8"));


    }
3.7.6:返回的结果
{"msg":"处理返回"}
{"msg":"登录成功""user"{"name":"post";"password":"post123456"}}
[{"name":"name1", "password":"password1"}, {"name":"name2", "password":"password2"}]

Process finished with exit code 0

jackson和gson在性能和效率上没有区别。Spring底层和json转换对象用的都是jackson。而我们开发的时候基本上都会用到Spring,尽量和他的应用和规则进行匹配。

3.8:下面我们做一下String字符串和Json字符串之间的转换。

3.8.1:首先在实体类中增加数据
private Date birth;

    public int getAge(){
        if (birth == null){
            return -1;
        }
        //生日的年份
        int brithYear = birth.getYear();
        //当前的年份
        int currentYear = new Date().getYear();
        //年龄
        return  currentYear - brithYear;
    }

    public void setAge(int age){

    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }
3.8.2:控制台代码:
/*
        请求体传递参数
        在我们使用post请求的时候,我们一般都是使用请求体进行传参,在非专业人事的眼中是隐藏路径的
         */
        HttpPost bodyParamsPost = new HttpPost("http://localhost:8080/bodyParams");

        /*
        定义请求协议体,设置请求参数,这是传字符串形式
        使用请求体传递参数的时候。需要定义请求格式,默认的是表单格式,
        通常我们都会把默认的请求格式进行修改成阶层格式
        使用URIbuilder构建的URI对象,就是请求体传递参数
         */
        User u1 = new User();
        u1.setName("name1");
        u1.setPassword("password1");
        User u2 = new User();
        u2.setName("name2");
        u2.setPassword("password2");
        List<User> users = new ArrayList<>();
        users.add(u1);
        users.add(u2);
        // 把集合users -> JSON字符串
        // 创建Jackson中的转换器对象
        ObjectMapper objectMapper = new ObjectMapper();

        /*
        java对象返回json格式字符串,不是所有的java对象都能转换为json格式的字符串
        java字符串转换为json格式字符串的时候是遵循一个原则
        默认get对应的property进行转换拼一个字符串。
        补充:
        property - 类型中getter和setter的命名。去除set|get,剩余部分首字母转小写。
        <bean><property name="abc"></property></bean>
        field - 类型中定义的实例变量。
         */
        String paramsString = objectMapper.writeValueAsString(users);

        System.out.println(paramsString);



        /*这是一个集合的表达形式json格式字符串,表示请求参数,一个List<User>
        但是这里面的toString方法不能直接用,这里是我修=修改过的toString方法。
        String paramsString = "["+u1.toString()+","+u2.toString()+"]";
         */
        /*
        StringEntity除了可以传字符串(String)、字符集(Charset)和请求体的格式(mimType)
         */
        HttpEntity entity = new StringEntity(paramsString,"application/json","UTF-8");

        /*
        给响应体是同一个类型,它所代表的就是协议体,当两个子类型分别是响应协议体和请求协议体
        面向父类的方式进行开发的
         */
        bodyParamsPost.setEntity(entity);
        System.out.println(EntityUtils.toString(client.execute(bodyParamsPost).getEntity(),"UTF-8"));

3.8.3:返回的结果:
{"msg":"处理返回"}
{"msg":"登录成功""user"{"name":"post";"password":"post123456"}}
[{"name":"name1","password":"password1","birth":null,"age":-1},{"name":"name2","password":"password2","birth":null,"age":-1}]
[{"name":"name1", "password":"password1"}, {"name":"name2", "password":"password2"}]

上面是已完成的代码:把String字符串转换为json格式字符串,如果我们想把json格式字符串转换为String对象怎么办?反向处理具体的操作如下:

 /*
        给响应体是同一个类型,它所代表的就是协议体,当两个子类型分别是响应协议体和请求协议体
        面向父类的方式进行开发的
         */
        bodyParamsPost.setEntity(entity);
        /*System.out.println(EntityUtils.toString(client.execute(bodyParamsPost).getEntity(),"UTF-8"));*/
        String responseString  = EntityUtils.toString(client.execute(bodyParamsPost).getEntity(), "UTF-8");

        //这是一个但对象,从下标1开始到,结束。包含开始下标不包含结束下标
        String userstring = responseString.substring(1, responseString.indexOf("},") + 1);

        User responseUser = objectMapper.readValue(userstring,User.class);

        System.out.println(responseUser);

        //构建一个Jackson识别的Java类型映射,以下是集合的转换方式
        JavaType valueType =
                objectMapper.getTypeFactory().constructParametricType(List.class, User.class);
        List<User> list = objectMapper.readValue(responseString, valueType);
        System.out.println(list);

返回的结果如下:

{"msg":"处理返回"}
{"msg":"登录成功""user"{"name":"post";"password":"post123456"}}
[{"name":"name1","password":"password1","birth":null,"age":-1},{"name":"name2","password":"password2","birth":null,"age":-1}]
{"name":"name1", "password":"password1"}
[{"name":"name1", "password":"password1"}, {"name":"name2", "password":"password2"}]

Process finished with exit code 0

System.out.println(responseUser);

    //构建一个Jackson识别的Java类型映射,以下是集合的转换方式
    JavaType valueType =
            objectMapper.getTypeFactory().constructParametricType(List.class, User.class);
    List<User> list = objectMapper.readValue(responseString, valueType);
    System.out.println(list);

返回的结果如下:

```java
{"msg":"处理返回"}
{"msg":"登录成功","user"{"name":"post";"password":"post123456"}}
[{"name":"name1","password":"password1","birth":null,"age":-1},{"name":"name2","password":"password2","birth":null,"age":-1}]
{"name":"name1", "password":"password1"}
[{"name":"name1", "password":"password1"}, {"name":"name2", "password":"password2"}]

Process finished with exit code 0

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java—RPC:远程过程调用(1) 的相关文章

随机推荐

  • lzma算法分析

    lzma算法分析 这几天在公司主要在做压缩相关 记录一下所得 目前业界主流的压缩算法感觉并不多 好用的就Huffman lz系列 其他的像差分编码 vlq编码 感觉只能做个数据预处理 或者一种小范围的压缩 lz系列有很多 主要有lz77 l
  • 禁用系统【快应用】,停止【快应用】自动弹出

    快应用 九大厂商同时宣布建立即时应用生态发展联盟 通过统一标准让开发者低成本接入 快应用 在研发接口 场景接入 服务能力和接入方式上建设标准平台 以平台化的生态模式对个人开发者和企业开发者全品类开放 此次九大厂商共建 快应用 标准和平台 最
  • C语言:操作符以及部分表达式介绍

    目录 1 操作符 1 1 算数操作符 1 2 移位操作符 1 3 位操作符 1 4 1 赋值操作符 1 4 2 复合赋值符 1 5 单目操作符 1 6 关系操作符 1 7 逻辑操作符 1 8 条件操作符 1 9 逗号操作符 1 10 下标引
  • udp发包结合tkinter

    import socket import tkinter from tkinter import filedialog from tkinter filedialog import def action 获取输入框内容 date entry
  • 深度学习双显卡配置_更新深度学习装备:双(1080Ti)显卡装机实录

    前言 之前一直在装有一张1080Ti的服务器上跑代码 但是当数据量超过10W 图像数据集 的时候 训练时就稍微有点吃力了 速度慢是一方面 关键显存存在瓶颈 导致每次训练的batch size不敢调的过高 batch size与训练结果存在一
  • 播放器实战22 解决花屏与卡顿问题

    1 内存对齐 1 1什么是内存对齐 在C语言中 结构是一种复合数据类型 其构成元素既可以是基本数据类型 如int long float等 的变量 也可以是一些复合数据类型 如数组 结构 联合等 的数据单元 在结构中 编译器为结构的每个成员按
  • 小熊派笔记2

    GPIO案例 GPIO接口函数 初始化 wifiiot gpio h接口 wifiiot gpio ex h接口 扩展函数 设置GPIO拉力和驱动器强度 LED对应的gpio引脚是gpio2通过控制gpio2输出的电平信号来实现闪烁 设置
  • 三极管和场效应管-易错点

    NPN三极管是电流控制器件 共发射极电路中 放大区 Ice Ib x Vbe正偏 Vbc反偏 电势 Vc Vb Ve 饱和区 Ice Ib x 两个都正偏 电势 Vb Vc Ve Vce之间是饱和管压降Vces 截止区 Ice 0 两个都反
  • VerilogHDL实现除法操作

    硬件电路中实现除法操作一般基于两种方式 乘法操作和减法操作 基于减法的除法器 对于32位的无符号除法 被除数a除以除数b 他们的商和余数位数一定不超过32位 首先将a转换为32位 b也转换为32位 在每周期的开始 先将a左移一位 末尾补0
  • 如何知道你的Linux内核占用的内存大小?

    如何知道你的Linux内核占用的内存大小 1 代码段等 2 kernel heap 2 1 kmalloc 2 2 vmalloc 3 进程的页表 4 内核占用内存大小总和 1 代码段等 内核所需的代码段 bss段 内核栈等 dmesg g
  • 双调排序算法的实现(C++)

    双调排序算法的实现 C 双调排序 Bitonic Sort 是一种并行排序算法 它在某些情况下比传统的排序算法具有更好的性能 该算法的特点是可以通过并行比较和交换操作来对元素进行排序 适用于并行计算环境 本文将介绍双调排序算法的实现 并提供
  • subList截图数据集合,便于分页或分批次保存至数据库

    import java util ArrayList import java util List public class subList param list 待切割集合 param len 集合按照多大size来切割 param
  • ZNYQ初体验,持续记录中...

    首先在VIVADO中创建zynq PS核 步骤如下 如下新建工程 新建 block design add ip 选择zynq7 processing system 如下图所示 双击打开配置界面如下 下面我们简要地介绍一下页面导航面板中各个页
  • 解决页面禁止拷贝的问题

    众所周知 像这种禁止的动作一般都是网页中的javascript在作怪 那么 我们直接把他禁用就好了吖 其实 最简单的 在你前面网页的导航栏里面输入javascript void 就可以尽情的白嫖了
  • go语言 FindWindow

    Go 语言中的 FindWindow 函数是用于查找窗口句柄的函数 它是由 Windows API 提供的 在 Go 中通过 syscall 包来调用 用法示例 packagemain import fmt syscall unsafe v
  • 有趣的数据结构算法5——利用循环链表解决Josephus问题

    有趣的数据结构算法5 利用循环链表解决Josephus问题 题目复述 解题思路 实现代码 GITHUB下载连接 本次教程主要讲述如何利用循环链表解决Josephus问题 题目复述 据说著名犹太历史学家 Josephus有过以下的故事 在罗马
  • Selenium碰到的异常记录

    Java版本的Selenium异常记录 1 没有找到类的异常 NoClassDefFoundError 异常如下 Exception in thread main java lang NoClassDefFoundError com goo
  • 记录Android开发中SELINUX权限问题

    记录Android开发中SELINUX权限和用户权限问题 在安卓开发中 当linux内核中配置了SELINUX权限管理 访问硬件相关的设备文件 led tty等 时 如果没有对文件和访问文件的程序设置selinux的权限 就有可能报如下错误
  • 编写java程序151条建议读书笔记(20)

    建议139 大胆采用开源工具 MVC框架有Structs 也有Spring MVC WebWorker IoC容器有Spring 也有Coolgle Guice ORM有Hibernate MyBatis 日志有经典的log4j 崭新的lo
  • Java—RPC:远程过程调用(1)

    Java RPC 远程过程调用 1 在我们学习RPC的过程中 首先我们先认识一下项目结构在发展中干的变化 一 项目结构变化 1 单体结构 单体结构又叫单一项目 在我们所认识的传统项目基本上都是单一项目 j可是在互联网逐步发展的过程中 逐渐的