Netty(11)序列化/反序列化、Netty参数

序列化与反序列化

序列化,反序列化主要用在消息正文的转换上

  • 序列化时,需要将 Java 对象变为要传输的数据(可以是 byte[],或 json 等,最终都需要变成 byte[])
  • 反序列化时,需要将传入的正文数据还原成 Java 对象,便于处理

在之前的自定义协议的时候,使用了序列化与反序列化;但是使用的是jdk自带的序列化和反序列化。如下:

// 反序列化
byte[] body = new byte[bodyLength];
byteByf.readBytes(body);
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(body));
Message message = (Message) in.readObject();
message.setSequenceId(sequenceId);

// 序列化
ByteArrayOutputStream out = new ByteArrayOutputStream();
new ObjectOutputStream(out).writeObject(message);
byte[] bytes = out.toByteArray();

Serializer 接口

在这个接口中,定义了抽象方法,可以有许多的实现

public interface Serializer {

    // 反序列化方法
    <T> T deserialize(Class<T> clazz, byte[] bytes);

    // 序列化方法
    <T> byte[] serialize(T object);

}

实现

java


@Override
public <T> T deserialize(Class<T> clazz, byte[] bytes) {
    try {
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
        return (T) ois.readObject();
    } catch (IOException | ClassNotFoundException e) {
        throw new RuntimeException("反序列化失败", e);
    }
}

@Override
public <T> byte[] serialize(T object) {
    try {
    	//拿到字节数据
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        //将object对象进行转换
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(object);
        return bos.toByteArray();
    } catch (IOException e) {
        throw new RuntimeException("序列化失败", e);
    }
}

json

@Override
public <T> T deserialize(Class<T> clazz, byte[] bytes) {
    Gson gson = new GsonBuilder().registerTypeAdapter(Class.class, new Serializer.ClassCodec()).create();
    String json = new String(bytes, StandardCharsets.UTF_8);
    return gson.fromJson(json, clazz);
}

@Override
public <T> byte[] serialize(T object) {
    Gson gson = new GsonBuilder().registerTypeAdapter(Class.class, new Serializer.ClassCodec()).create();
    String json = gson.toJson(object);
    return json.getBytes(StandardCharsets.UTF_8);
}


参数调优

CONNECT_TIMEOUT_MILLIS

CONNECT_TIMEOUT_MILLIS

  • 属于 SocketChannal 参数
  • 用在客户端建立连接时,如果在指定毫秒内无法连接,会抛出 timeout 异常

SO_TIMEOUT 主要用在阻塞 IO,阻塞 IO 中 accept,read 等都是无限等待的,如果不希望永远阻塞,使用它调整超时时间

  • 这个参数不是用在netty里,也不用在Nio里的,其只是用在最传统的ServerSocket、Socket的阻塞IO编程中

客户端.option()

客户端通过 .option() 方法配置参数 给 SocketChannel 配置参数

Bootstrap bootstrap = new Bootstrap();
//配置参数, 300毫秒
bootstrap .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000)

服务器端

new ServerBootstrap().option() // 是给 ServerSocketChannel 配置参数

new ServerBootstrap().childOption() // 给 SocketChannel 配置参数

SO_BACKLOG

属于 ServerSocketChannal 参数

三次握手

半连接队列:还未完成三次握手的连接信息
全连接队列:已经完成三次握手的连接信息

client server syns queue(半连接队列) accept queue(全连接队列) bind() listen() connect() 1. SYN SYN_SEND put SYN_RCVD 2. SYN + ACK ESTABLISHED 3. ACK put ESTABLISHED accept() client server syns queue(半连接队列) accept queue(全连接队列)
  1. 第一次握手,client 发送 SYN 到 server,状态修改为 SYN_SEND,server 收到,状态改变为 SYN_REVD,并将该请求放入 sync queue 队列
  2. 第二次握手,server 回复 SYN + ACK 给 client,client 收到,状态改变为 ESTABLISHED,并发送 ACK 给 server
  3. 第三次握手,server 收到 ACK,状态改变为 ESTABLISHED,将该请求从 sync queue 放入 accept queue

SO_BACKLOG

在 linux 2.2 之前,backlog 大小包括了两个队列的大小,在 2.2 之后,分别用下面两个参数来控制两个队列的大小

  • sync queue - 半连接队列
    • 大小通过 /proc/sys/net/ipv4/tcp_max_syn_backlog 指定,在 syncookies 启用的情况下,逻辑上没有最大值限制,这个设置便被忽略
  • accept queue - 全连接队列
    • 其大小通过 /proc/sys/net/core/somaxconn 指定,在使用 listen 函数时,内核会根据传入的 backlog 参数与系统参数取二者的较小值
      • backlog 是程序中控制全连接队列的一个方式,在Nio中有一个bind()方法,其可以接收两个参数:bind(8080, backlog)
    • 如果 accpet queue 队列满了,server 将发送一个拒绝连接的错误信息到 client
    • 全连接队列的大小作用决定可以有多少个客户端可以在队列中存放,如果客户端的连接超过队列的大小,就认为服务器处理连接达到上限了,就会报一个拒绝连接的错误

netty 中: 可以通过 option(ChannelOption.SO_BACKLOG, 值) 来设置大小

Bootstrap bootstrap = new Bootstrap();
//配置参数, 队列大小为2(一般设置1024,大一点)
bootstrap.option(ChannelOption.SO_BACKLOG, 2) 

断点的意义:使连接放入队列里面,但没有从队列中取出
在这里插入图片描述
如果debug启动后,开启三个客户端,由于断点,连接没有并没有从队列中拿出,超过两个连接了,所以会报错,如下:
在这里插入图片描述

backlog是如何调用的

查看这个变量是在何处被引用
第一步:找到这个方法的使用位置,可以查看在何处调用了这个方法
在这里插入图片描述
发现有三个地方对这个方法进行了调用
在这里插入图片描述
nio中的不需要看,直接看netty里面的

第二步:进入netty调用这个方法的位置
在这里插入图片描述
进入方法
在这里插入图片描述
第三步:查看config这个参数从何来
在这里插入图片描述

第四步:查看其实现,进入Nio的
在这里插入图片描述
第五步:查找backlog获取的方法
在这里插入图片描述
在这里插入图片描述
第六步:进入NetUtil查看其是如何赋值的
在这里插入图片描述

ulimit -n

属于操作系统参数

限制一个进程能够同时打开最大的文件描述服务的数量

文件描述服务:简称FD,如普通文件,socket都是使用其来表示的

需要在linux系统里面去进行配置

TCP_NODELAY

属于 SocketChannal 参数

netty对这个参数的默认值是false:默认开启了nagle算法

如果服务器希望消息能够及时发出去,所以应该将这个参数设为true

可以在netty代码中去调整

Bootstrap bootstrap = new Bootstrap();
//配置参数
bootstrap.option(ChannelOption.TCP_NODELAY, true) 

SO_SNDBUF & SO_RCVBUF

这两个参数决定了滑动窗口的上限:

  • SO_SNDBUF 属于 SocketChannal 参数
  • SO_RCVBUF 既可用于 SocketChannal 参数,也可以用于 ServerSocketChannal 参数(建议设置到 ServerSocketChannal 上)

目前不需要去调整这两个参数,操作系统会自动对这两个参数进行调整

可以在netty代码中去调整

ALLOCATOR

ByteBuf的分配器:

  • 属于 SocketChannal 参数
  • 用来分配 ByteBuf, ctx.alloc()


RCVBUF_ALLOCATOR

  • 属于 SocketChannal 参数
  • 控制 netty 接收缓冲区大小
  • 负责入站数据的分配,决定入站缓冲区的大小(并可动态调整),统一采用 direct (直接内存
    ),具体池化还是非池化由 allocator 决定
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

?abc!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值