博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Netty3 - 自定义序列化协议(1)
阅读量:4041 次
发布时间:2019-05-24

本文共 6522 字,大约阅读时间需要 21 分钟。

一:前期准备工作

1.要实现对象的序列化,先要了解一下java的8种基本数据类型及相关的储存字节大小

8中类型所占字节和位数如下:

类型 占用字节  占用位数 说明
byte     1 8  
short     2 16  
int     4 32  
long     8 64  
float     4 32  
double  8 64  
char 2 16  
boolean 1 8

实际上占用一个字节还是一个位,在或者是四个字节?

 

 

 

 

 

 

 

 

 

 

 

参阅:

是否通过验证方式:

1.通过查看生成class文件的内部结构来验证了 ,可以用jdk 自带的工具: javap -verbose TestBoolean -> NO:自码文件中的boolean 类型只是用Z来标注,而并没有转化成其它的数据类型

2,hexdump -C filename可以查看二进制文件  ->  hexdump -C Test.class  

下载 hexdump 

二进制:

十进制:

十六进制: 0x就是代表十六进制,0x00 - 0xFF 

对于二进制来说,8位二进制我们称之为一个字节,二进制的表达范围值是从0b00000000~0b11111111,而我们程序中用十六进制表示的时候就是从0x00到0xFF,这里教大家一个二进制转换十进制和十六进制的方法,二进制4位一组,遵循8,4,2,1的规律比如 1010,那么从最高位开始算,数字大小是8*1+4*0+2*1+1*0 = 10,那么十进制就是10,十六进制就是0xA。尤其二进制转十六进制的时候,十六进制一位刚好是和二进制的4位相互对应的

2.负数在计算机内是如何表示的

原码:

反码:

补码:

 

3.字节序列化模式:大端模式与小端模式

大端模式:高位在前

小端模式:低位在前

示例:

/** * 以大端模式将int转成byte[] */public static byte[] intToBytesBig(int value) {    byte[] src = new byte[4];    src[0] = (byte) ((value >> 24) & 0xFF);    src[1] = (byte) ((value >> 16) & 0xFF);    src[2] = (byte) ((value >> 8) & 0xFF);    src[3] = (byte) (value & 0xFF);    return src;}/** * 以小端模式将int转成byte[] * * @param value * @return */public static byte[] intToBytesLittle(int value) {    byte[] src = new byte[4];    src[3] = (byte) ((value >> 24) & 0xFF);    src[2] = (byte) ((value >> 16) & 0xFF);    src[1] = (byte) ((value >> 8) & 0xFF);    src[0] = (byte) (value & 0xFF);    return src;}/** * 以大端模式将byte[]转成int */public static int bytesToIntBig(byte[] src, int offset) {    int value;    value = (int) (((src[offset] & 0xFF) << 24)            | ((src[offset + 1] & 0xFF) << 16)            | ((src[offset + 2] & 0xFF) << 8)            | (src[offset + 3] & 0xFF));    return value;}/** * 以小端模式将byte[]转成int */public static int bytesToIntLittle(byte[] src, int offset) {    int value;    value = (int) ((src[offset] & 0xFF)            | ((src[offset + 1] & 0xFF) << 8)            | ((src[offset + 2] & 0xFF) << 16)            | ((src[offset + 3] & 0xFF) << 24));    return value;}

 

二:基本数据类型的序列化操作

查看示例代码

package custserialize;import org.jboss.netty.buffer.ChannelBuffer;import org.jboss.netty.buffer.ChannelBuffers;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.nio.ByteBuffer;import java.util.Arrays;/** * 基本数据类型是如何序列化的 *  首先也就是要确定基本数据类型是如何转化成字节的。通常有两种方式 *  大端:高位在前 *  小端:低位在前 */public class TypeSerialize {    public static void main(String[] args) throws Exception{        short age=120;        int sales=123456;        //1:字节输出流        System.out.println("************************JDK api*******************************");        ByteArrayOutputStream outputStream=new ByteArrayOutputStream();        outputStream.write(shortToBytes(age));        outputStream.write(intToBytes(sales));        byte[] bytes=outputStream.toByteArray();        System.out.println("result bytes="+Arrays.toString(bytes));        //解析,按照写入的顺序读出相应的字节大小        ByteArrayInputStream inputStream=new ByteArrayInputStream(bytes);        byte[] ageByte=new byte[2];        byte[] saleByte=new byte[4];        inputStream.read(ageByte);        inputStream.read(saleByte);        System.out.println("age="+bytesToShort(ageByte));        System.out.println("sales="+bytesToInt(saleByte));//bytesToInt bytes2Int        //2.Nio的ByteBuffer,缺点就是必须先确定要分配的字节数组的大小,不能动态的进行扩容        System.out.println("**********************JDK NIO Api**************************************");        ByteBuffer buffer = ByteBuffer.allocate(4);        buffer.putInt(sales);        byte[] b1=buffer.array();        System.out.println("int byte="+Arrays.toString(b1));        System.out.println("reback ="+bytes2Int(b1));        //3.Netty中提供的ChannelBuffer        System.out.println("****************************Netty Api************************************");        ChannelBuffer channelBuffer = ChannelBuffers.dynamicBuffer();        channelBuffer.writeInt(10101);        channelBuffer.writeFloat(9999.99f);        channelBuffer.writeChar('A');        byte[] channelBufferBytes=new byte[channelBuffer.writerIndex()];//channelbuffer 写的位置        channelBuffer.readBytes(channelBufferBytes);        System.out.println("channel buffer bytes="+Arrays.toString(channelBufferBytes));        ChannelBuffer readChannelBuffer=ChannelBuffers.wrappedBuffer(channelBufferBytes);        System.out.println("netty int="+readChannelBuffer.readInt());        System.out.println("netty float="+readChannelBuffer.readFloat());        System.out.println("netty char="+readChannelBuffer.readChar());    }    /**     * 采用大端字节序列(即是先写高位,在写低位)     *  返回的字节数组中,byte[0]对应的是原数据位表示的最高位     * @param param     * @return     */    public static  byte[] shortToBytes(short param){        // short 在jdk的规范说明中占用2个字节        byte[] bytes=new byte[2];        bytes[0]=(byte)(param >> 1*8);        bytes[1]=(byte)(param >> 0*8);        return bytes;    }    /**         * 采用大端字节序列(即是先写高位,在写低位)     * 返回的字节数组中,byte[0]对应的是原数据位表示的最高位     * @param bytes     * @return     */    public static short bytesToShort(byte[] bytes){        short result=(short)( (bytes[0] << 1*8 )   // 第一痊为高位                |                (bytes[1] << 0*8)        );        return result;    }    /**     * 将int 类型转化为字节数组     * @param param     * @return     */    public static byte[] intToBytes(int param){        byte[] fbyte=new byte[4];//int 占用四个字节        fbyte[0] = (byte)(param >> 3*8);        fbyte[1] = (byte)(param >> 2*8);        fbyte[2] = (byte)(param >> 1*8);        fbyte[3] = (byte)(param >> 0*8);        return fbyte;    }    /**     *     * @param bytes     * @return     */    public static int bytesToInt(byte[] bytes){        return ( (bytes[0] & 0xFF) << 3*8) |                ( (bytes[1]  & 0xFF)<< 2*8) |                ( (bytes[2]  & 0xFF) << 1*8) |                ( (bytes[3]  & 0xFF) << 0*8);    }    /*****************************************************/    /**     * 大端方式     * @param bytes     * @return     */    private static int bytes2Int(byte[] bytes) {        int addr;        if (bytes.length == 1) {            addr = bytes[0] & 0xFF;        } else {            addr = bytes[0] & 0xFF;            addr = (addr << 8) | (bytes[1] & 0xff);            addr = (addr << 8) | (bytes[2] & 0xff);            addr = (addr << 8) | (bytes[3] & 0xff);        }        return addr;    }    /**     * 大端方式     * @param bytes 数组大端     * @return float     */    private float bytes2Float(byte[] bytes) {        int l;        l = bytes[0];        l &= 0xff;        l |= ((long) bytes[1] << 8);        l &= 0xffff;        l |= ((long) bytes[2] << 16);        l &= 0xffffff;        l |= ((long) bytes[3] << 24);        return Float.intBitsToFloat(l);    }}

 

 

 

 

 

 

 

 

 

 

转载地址:http://iwadi.baihongyu.com/

你可能感兴趣的文章
js判断数组内是否有重复值
查看>>
js获取url链接携带的参数值
查看>>
gdb 调试core dump
查看>>
gdb debug tips
查看>>
arm linux 生成火焰图
查看>>
linux和windows内存布局验证
查看>>
linux insmod error -1 required key invalid
查看>>
linux kconfig配置
查看>>
linux不同模块completion通信
查看>>
linux printf获得时间戳
查看>>
C语言位扩展
查看>>
linux dump_backtrace
查看>>
linux irqdebug
查看>>
git 常用命令
查看>>
linux位操作API
查看>>
uboot.lds文件分析
查看>>
uboot start.s文件分析
查看>>
没有路由器的情况下,开发板,虚拟机Ubuntu,win10主机,三者也可以ping通
查看>>
本地服务方式搭建etcd集群
查看>>
安装k8s Master高可用集群
查看>>