序列化,反序列化主要用在消息正文的转换上
序列化时,需要将 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();
在这个接口中,定义了抽象方法,可以有许多的实现
public interface Serializer {
// 反序列化方法
<T> T deserialize(Class<T> clazz, byte[] bytes);
// 序列化方法
<T> byte[] serialize(T object);
}
@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);
}
}
@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
属于 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 配置参数
属于 ServerSocketChannal 参数
半连接队列:还未完成三次握手的连接信息
全连接队列:已经完成三次握手的连接信息
在 linux 2.2 之前,backlog 大小包括了两个队列的大小,在 2.2 之后,分别用下面两个参数来控制两个队列的大小
syncookies
启用的情况下,逻辑上没有最大值限制,这个设置便被忽略通过 /proc/sys/net/core/somaxconn 指定
,在使用 listen 函数时,内核会根据传入的 backlog 参数与系统参数,取二者的较小值
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启动后,开启三个客户端,由于断点,连接没有并没有从队列中拿出,超过两个连接了,所以会报错,如下:
查看这个变量是在何处被引用
第一步:找到这个方法的使用位置,可以查看在何处调用了这个方法
发现有三个地方对这个方法进行了调用
nio中的不需要看,直接看netty里面的
第二步:进入netty调用这个方法的位置
进入方法
第三步:查看config这个参数从何来
第四步:查看其实现,进入Nio的
第五步:查找backlog获取的方法
第六步:进入NetUtil查看其是如何赋值的
属于操作系统参数
限制一个进程能够同时打开最大的文件描述服务的数量
文件描述服务:简称FD,如普通文件,socket都是使用其来表示的
需要在linux系统里面去进行配置
属于 SocketChannal 参数
netty对这个参数的默认值是false:默认开启了nagle算法
如果服务器希望消息能够及时发出去,所以应该将这个参数设为true
可以在netty代码中去调整
Bootstrap bootstrap = new Bootstrap();
//配置参数
bootstrap.option(ChannelOption.TCP_NODELAY, true)
这两个参数决定了滑动窗口的上限:
目前不需要去调整这两个参数,操作系统会自动对这两个参数进行调整
可以在netty代码中去调整
ByteBuf的分配器:
控制 netty 接收缓冲区大小