ZhouXiangの博客 后端工程师&机器学习爱好者

Java学习系列之协议栈

2019-10-22

本文系记录对Java中协议栈的学习资料,如有异议,欢迎联系我讨论修改。PS:图侵删!图片丢失请访问:传送门

Protubuf

Protobuf是由Google开发的一种平台无关、语言无关、可扩展且轻便高效的序列化数据结构的协议,可以用于网络通信和数据存储。适用于传输数据量大且网络环境不稳定的数据存储。

Protubuf的特点

Protubuf的优点

  • 平台无关,语言无关,可扩展;
  • 提供了友好的动态库,使用简单;
  • 解析速度快,比对应的XML快约20-100倍;
  • 序列化数据非常简洁、紧凑,与XML相比,其序列化之后的数据量约为1/3到1/10。

Protubuf的作用

  • 序列化:将数据结构或对象 转换成 二进制串 的过程
  • 反序列化:将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程

Protubuf的应用场景

传输数据量大&网络环境不稳定的数据存储、RPC 数据交换的需求场景,例如即时IM(QQ/微信)。

Protubuf所在的网络层次

Protubuf属于TCP/IP模型的应用层&OSI模型的表示层。

Protubuf与Xml序列化反序列化过程对比

由于编码方式简单(只需要简单的数学运算 = 位移等等),以及采用Protubuf自身的框架代码和编译器共同完成,所以序列化、反序列化速度非常快。

Protubuf序列化

  • 判断每个字段是否有设置值,有值才进行编码
  • 根据字段标识号&数据类型,将字段值通过不同的编码方式进行编码

Protubuf反序列化

  • 调用消息类的parseFrom(input)解析从输入流读入的二进制字节数据流

Xml反序列化

  • 从文件中读取出字符串
  • 将字符串转换为 XML 文档对象结构模型
  • 从 XML 文档对象结构模型中读取指定节点的字符串
  • 将该字符串转换成指定类型的变量

上述过程非常复杂。其中,将XML文件转换为文档对象结构模型的过程通常需要完成词法文法分析等大量消耗CPU的复杂计算。

Protubuf为什么压缩效果好

  • 采用了独特的编码方式,如Varint、Zigzag编码方式等等
  • 采用T-L-V的数据存储方式:减少了分隔符的使用 & 数据存储得紧凑

Protubuf与其他数据协议比较

Protubuf的消息定义

消息由至少一个字段组合而成,类似于C语言中的结构。每个字段都有一定的格式。
字段格式:限定修饰符① | 数据类型② | 字段名称③ | = | 字段编码值④ | [字段默认值⑤]

Protubuf的限定修饰符

  • 对于required的字段而言,初值是必须要提供的,否则字段的便是未初始化的。在Debug模式的buffer库下编译的话,序列化话的时候可能会失败,而且在反序列化的时候对于该字段的解析会总是失败的。所以,对于修饰符为required的字段,请在序列化的时候务必给予初始化。
  • 对于optional的字段而言,如果未进行初始化,那么一个默认值将赋予该字段,当然也可以指定默认值。
  • 对于repeated的字段而言,该字段可以重复多个,google提供的这个addressbook例子便有个很好的该修饰符的应用场景,即每个人可能有多个电话号码。在高级语言里面,我们可以通过数组来实现,而在proto定义文件中可以使用repeated来修饰,从而达到相同目的。当然,出现0次也是包含在内的。

Protubuf的数据类型

加密

对称加密

采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密。所谓对称,就是采用这种加密方法的双方使用方式用同样的密钥进行加密和解密。密钥是控制加密及解密过程的指令。算法是一组规则,规定如何进行加密和解密。对称加密具有速度快的特点,但是安全性不足。
对称加密算法中常用的算法有:DES、3DES、TDEA、Blowfish、RC2、RC4、RC5、IDEA、SKIPJACK等。

非对称加密

非对称加密算法需要两个密钥:公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。 非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将公钥公开,需要向甲方发送信息的其他角色(乙方)使用该密钥(甲方的公钥)对机密信息进行加密后再发送给甲方;甲方再用自己私钥对加密后的信息进行解密。甲方想要回复乙方时正好相反,使用乙方的公钥对数据进行加密,同理,乙方使用自己的私钥来进行解密。另一方面,甲方可以使用自己的私钥对机密信息进行签名后再发送给乙方;乙方再用甲方的公钥对甲方发送回来的数据进行验签。甲方只能用其私钥解密由其公钥加密后的任何信息。 非对称加密算法的保密性比较好,它消除了最终用户交换密钥的需要。

非对称密码体制的特点:算法强度复杂、安全性依赖于算法与密钥但是由于其算法复杂,而使得加密解密速度没有对称加密解密的速度快。对称密码体制中只有一种密钥,并且是非公开的,如果要解密就得让对方知道密钥。所以保证其安全性就是保证密钥的安全,而非对称密钥体制有两种密钥,其中一个是公开的,这样就可以不需要像对称密码那样传输对方的密钥了。这样安全性就大了很多。

工作原理:

  • 1.A要向B发送信息,A和B都要产生一对用于加密和解密的公钥和私钥。
  • 2.A的私钥保密,A的公钥告诉B;B的私钥保密,B的公钥告诉A。
  • 3.A要给B发送信息时,A用B的公钥加密信息,因为A知道B的公钥。
  • 4.A将这个消息发给B(已经用B的公钥加密消息)。
  • 5.B收到这个消息后,B用自己的私钥解密A的消息。其他所有收到这个报文的人都无法解密,因为只有B才有B的私钥。

MD5

Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护。MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。

特点

  • 压缩性:任意长度的数据,算出的MD5值长度都是固定的。
  • 容易计算:从原数据计算出MD5值很容易。
  • 抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
  • 强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
  • 非对称性加密

RSA

https://blog.csdn.net/jijianshuai/article/details/80582187

JSON

JSON起源于1999年的JS语言规范ECMA262的一个子集(即15.12章节描述了格式与解析),后来2003年作为一个数据格式ECMA404(很囧的序号有不有?)发布。2006年,作为rfc4627发布,这时规范增加到18页,去掉没用的部分,十页不到。

JSON结构

  • 只有两种基本结构:对象内的键值对集合结构和数组,对象用{}表示、内部是”key”:”value”,数组用[]表示,不同值用逗号分开.
  • 基本数值有7个: false / null / true / object / array / number / string
  • 结构可以嵌套,进而可以用来表达复杂的数据,例如:
    {
     "Image": {
         "Width":  800,
         "Height": 600,
         "Title":  "View from 15th Floor",
         "Thumbnail": {
             "Url":    "http://www.example.com/image/481989943",
             "Height": 125,
             "Width":  "100"
         },
         "IDs": [116, 943, 234, 38793]
       }
    }
    

JSON优缺点

优点
  • 基于纯文本,阅读性好.
  • 规范简单,容易处理,开箱即用,特别是JS类的ECMA脚本里是内建支持的,可以直接作为对象使用.
  • 平台无关性,因为类型和结构都是平台无关的,而且好处理,容易实现不同语言的处理类库,可以作为多个不同异构系统之间的数据传输格式协议,特别是在HTTP/REST下的数据格式.
缺点
  • 性能一般,文本表示的数据一般来说比二进制大得多,在数据传输上和解析处理上都要更影响性能.
  • 缺乏schema,跟同是文本数据格式的XML比,在类型的严格性和丰富性上要差很多.

JSON编码指南

  • 属性名和值都是用双引号,不要把注释写到对象里面,对象数据要简洁
  • 不要随意结构化分组对象,推荐是用扁平化方式,层次不要太复杂
  • 命名方式要有意义,比如单复数表示
  • 驼峰式命名,遵循Bean规范
  • 使用版本来控制变更冲突
  • 对于一些关键字,不要拿来做key
  • 如果一个属性是可选的或者包含空值或null值,考虑从JSON中去掉该属性,除非它的存在有很强的语义原因
  • 序列化枚举类型时,使用name而不是value
  • 日期要用标准格式处理
  • 设计好通用的分页参数
  • 设计好异常处理

详细参考:https://github.com/darcyliu/google-styleguide/blob/master/JSONStyleGuide.md

JSON应用场景

  • 内部后台系统之间的数据传输,此种情况下基于HTTP的JSON格式其实没有优势.
  • 前后台之间的API调用,典型的是前端作为React/VUE/AngularJS/ExtJS等框架做的,前后端使用JSON交互.
  • 提供给第三方的开发接口API.

Jackson常用API

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.zx</groupId>
    <artifactId>json</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.5</version>
        </dependency>
    </dependencies>

</project>
Demo
public class User {

    public User() {

    }

    public User(String name, Integer age, Date date, String email) {
        this.name = name;
        this.age = age;
        this.birthday = date;
        this.email = email;
    }

    private String name;
    private Integer age;
    private Date birthday;
    private String email;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    @Override
    public String toString() {
        return "com.zx.json.User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", birthday=" + birthday +
                ", email='" + email + '\'' +
                '}';
    }

}
package com.zx.json;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author :Alitria
 * @date :Created in 2019/1/16 17:37
 * @description:
 * @modified By:
 * @version: $
 */
public class JacksonDemo {

    /**
     * ObjectMapper是JSON操作的核心,Jackson的所有JSON操作都是在ObjectMapper中实现。
     * ObjectMapper有多个JSON序列化的方法,可以把JSON字符串保存File、OutputStream等不同的介质中。
     * writeValue(File arg0, Object arg1)把arg1转成json序列,并保存到arg0文件中。
     * writeValue(OutputStream arg0, Object arg1)把arg1转成json序列,并保存到arg0输出流中。
     * writeValueAsBytes(Object arg0)把arg0转成json序列,并把结果输出成字节数组。
     * writeValueAsString(Object arg0)把arg0转成json序列,并把结果输出成字符串。
     */

    /*
        Java对象转Json字符串
     */
    public static void pojo2json() throws ParseException, JsonProcessingException {
        User user = new User();
        user.setName("zhangsan");
        user.setEmail("zhangsan@163.com");
        user.setAge(20);
        SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");
        user.setBirthday(dateformat.parse("1996-10-01"));
        ObjectMapper mapper = new ObjectMapper();
        String json = mapper.writeValueAsString(user);
        System.out.println(json);
    }
    /*
        Java-List转Json字符串
     */
    public static void pojoList2json() throws ParseException, JsonProcessingException {
        List<User> users = new ArrayList<User>();
        User user = new User();
        user.setName("zhangsan");
        user.setEmail("zhangsan@163.com");
        user.setAge(20);
        SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");
        user.setBirthday(dateformat.parse("1996-10-01"));
        users.add(user);
        ObjectMapper mapper = new ObjectMapper();
        String jsonlist = mapper.writeValueAsString(users);
        System.out.println(jsonlist);
    }
    /*
        Json字符串转Java对象
     */
    public static void json2pojo() throws Exception {
        String jsonInStr = "{\"name\":\"zhangsan\",\"age\":20,\"birthday\":844099200000,\"email\":\"zhangsan@163.com\"}";
        ObjectMapper mapper = new ObjectMapper();
        User user = mapper.readValue(jsonInStr, User.class);
        System.out.println(user.getName());
        System.out.println(user.getEmail());
        System.out.println(user.getBirthday());
        System.out.println(user.getAge());
    }
    /*
        Json字符串数组转Java_List
     */
    public static void jsonArray2pojo() throws Exception {
        String jsonInStr = "[{\"name\":\"zhangsan\",\"age\":20,\"birthday\":844099200000,\"email\":\"zhangsan@163.com\"}]";
        ObjectMapper mapper = new ObjectMapper();
        List<User> userList = mapper.readValue(jsonInStr, new TypeReference<List<User>>() {});
        for(User user: userList) {
            System.out.println(user.getName());
            System.out.println(user.getEmail());
            System.out.println(user.getBirthday());
            System.out.println(user.getAge());
        }
    }
    /*
        Json字符串转Map
     */
    public static void json2map() throws IOException {
        String jsonInStr = "{\"name\":\"zhangsan\",\"age\":20,\"birthday\":844099200000,\"email\":\"zhangsan@163.com\"}";
        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> map = mapper.readValue(jsonInStr, new TypeReference<HashMap<String, Object>>(){});
        for(Map.Entry<String, Object> entry: map.entrySet()) {
            System.out.println(entry.getKey()+"  "+entry.getValue());
        }
    }
    /*
        Json字符串转节点
     */
    public static void json2node() throws IOException {
        String jsonInStr = "{\"name\":\"zhangsan\",\"age\":20,\"birthday\":844099200000,\"email\":\"zhangsan@163.com\"}";
        ObjectMapper mapper = new ObjectMapper();
        JsonNode root = mapper.readTree(jsonInStr);
        System.out.println(root.get("name").asText());
    }
    /*
        Json字符串转数组
     */
    public static void jsonArray2Array() throws IOException {
        String jsonInStr = "[" +
                "{\"name\":\"zhangsan\",\"age\":20,\"birthday\":844099200000,\"email\":\"zhangsan@163.com\"}, " +
                "{\"name\":\"zhangsan\",\"age\":20,\"birthday\":844099200000,\"email\":\"zhangsan@163.com\"}" +
                "]";
        ObjectMapper mapper = new ObjectMapper();
        User[] array = mapper.readValue(jsonInStr, new TypeReference<User[]>(){});
        for(int i=0; i<array.length; i++) {
            System.out.println(array[i].getAge());
            System.out.println(array[i].getBirthday());
            System.out.println(array[i].getEmail());
            System.out.println(array[i].getName());
        }
    }
    /*
        递归遍历Json字符串
     */
    public static void jsonLeaf(JsonNode node) {
        if(node.isValueNode()) {
            System.out.println(node.getNodeType()+"  "+node.toString());
            return;
        }
        if(node.isObject()) {
            Iterator<Map.Entry<String, JsonNode>> it = node.fields();
            while (it.hasNext()) {
                Map.Entry<String, JsonNode> entry = it.next();
                jsonLeaf(entry.getValue());
            }
        }
        if(node.isArray()) {
            Iterator<JsonNode> it = node.iterator();
            while (it.hasNext()) {
                jsonLeaf(it.next());
            }
        }
    }
    public static void completedJsonRead() throws IOException {
//        String jsonInStr = "[{\"id\":\"1\"}, {\"name\":\"zhangsan\",\"age\":20,\"birthday\":844099200000,\"email\":\"zhangsan@163.com\"}]";
        String jsonInStr = "[{\"id\":\"1\"}, {\"ip\":{\"addr\":\"10.1.18.3\"}},{\"name\":\"zhangsan\",\"age\":20,\"birthday\":844099200000,\"email\":\"zhangsan@163.com\"}]";
        ObjectMapper mapper = new ObjectMapper();
        JsonNode node = mapper.readTree(jsonInStr);
        jsonLeaf(node);
    }

    public static void main(String[] args) throws Exception, ParseException, IOException, ClassNotFoundException {
        completedJsonRead();
    }

}

FastJson常见Api

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">
    <parent>
        <artifactId>json</artifactId>
        <groupId>com.zx</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>fastjson</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.54</version>
        </dependency>
    </dependencies>
</project>
Demo
public class User {
    String username;
    String password;

    public User() {
    }
    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    @Override
    public String toString() {
        return "User [username=" + username + ", password=" + password + "]";
    }
}
public class UserGroup {
    private String name;
    private List<User> users = new ArrayList<User>();
    public UserGroup(){}
    public UserGroup(String name,List<User> users){
        this.name = name;
        this.users = users;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public List<User> getUsers() {
        return users;
    }
    public void setUsers(List<User> users) {
        this.users = users;
    }
    @Override
    public String toString() {
        return "UserGroup [name=" + name + ", users=" + users + "]";
    }
}
public class Demo {
    /*
        Java实例转Json字符串
     */
    public static void pojo2json() {
        User user = new User("zx", "950519");
        String json = JSON.toJSONString(user);
        System.out.println(json);
    }
    /*
        Java_List实例转Json字符串(数组)
     */
    public static void pojo_lits2json() {
        User user_1 = new User("zx", "950519");
        User user_2 = new User("lzx", "950608");
        List<User> userList = new ArrayList<User>();
        userList.add(user_1);
        userList.add(user_2);
        String json = JSON.toJSONString(userList);
        System.out.println(json);
    }
    /*
        Java组合实例转Json字符串(数组)
     */
    public static void completedPojo2json() {
        User user_1 = new User("zx", "950519");
        User user_2 = new User("lzx", "950608");
        List<User> userList = new ArrayList<User>();
        userList.add(user_1);
        userList.add(user_2);
        UserGroup userGroup = new UserGroup("1001", userList);
        String json = JSON.toJSONString(userList);
        System.out.println(json);
    }
    /*
        json字符串转Java实例
     */
    public static void json2pojo() {
        String strInJson = "{'password':'123456','username':'dmego'}";
//        User user = JSON.parseObject(strInJson, User.class);
        User user = JSON.parseObject(strInJson, new TypeReference<User>(){});
        System.out.println(user.toString());
    }
    /*
        json字符串转Java_List
     */
    public static void json2pojoList() {
        String strInJson = "[{'password':'123123','username':'zhangsan'},{'password':'321321','username':'lisi'}]";
        List<User> userList = JSONArray.parseObject(strInJson, new TypeReference<ArrayList<User>>() {});
        for(User user: userList) {
            System.out.println(user.getUsername()+"  "+user.getPassword());
        }
    }
    /*
        json字符串转复杂Java实例
     */
    public static void json2CompletedPojo() {
        String strInJson = "{'name':'userGroup_2008','users':[{'password':'123123','username':'zhangsan'},{'password':'321321','username':'lisi'}]}";
        UserGroup userGroup = JSON.parseObject(strInJson, new TypeReference<UserGroup>(){});
        System.out.println(userGroup.getName());
    }
    /*
        校验是否是合法Json字符串
     */
    public static boolean judgeIfValidJson(String strInJson) {
        try {
            JSONObject.parseObject(strInJson);
        } catch (JSONException ex) {
            try {
                JSONObject.parseArray(strInJson);
            } catch (JSONException ex1) {
                return false;
            }
        }
        return true;
    }

    public static void main(String[] args) {
          System.out.println(judgeIfValidJson("{ password':'123456','username':'dmego'}"));
    }
}

Similar Posts

Comments