1.序列化
(1)什么是序列化?
Java的序列化是把对象转换成有序字节流的过程。以便进行网络传输或者保存到本地。
(2)为什么要序列化?
当两个进程进行远程通信时,如果需要发送各种各样的数据,文本、音频、文件、对象等,
在发送这些数据之前,都要把这些数据变成二进制流,才能在网络上进行传输,序列化就
是把这些数据变成有序字节流的过程。
2.序列化工具
(1)Java原生序列化
缺点:
无法跨语言
序列化之后结果太大
序列化效率差
(2)Hessian
(3)thrift
(4)JBoss Marshalling
(5)kryo
(6)MessagePack、kryo、hession和Json
编码和解码
3.TCP的拆包和粘包
先看两个应用场景:
(1)客户端和服务端建立一个连接,客户端发送一条消息,各户端关闭与服务端的连接
(2)客户端和服务端建立一个连接,客户端发一条消息,客户端再次发送消息,客户端关闭与服务端的连接
I. 正常包:对于第一种情况,服务端在不停接收客户端传过来的数据,当客户端断开连接后,服务端知道数据接收完了,开始处理。
II.粘包:对于第二种情况,服务端就读到了一个数据包,如果还是用同一个逻辑处理就有问题了,因为服务端会把两条消息按照一条消息来处理。它不知道第一条
消息在哪结束,第二条消息从哪开始,即两条消息被放到了同一个数据包,这种情况就叫做粘包
III.拆包:服务器收到了两个数据包,第一个数据包只包含了第一条消息的一部分,第二个数据包含了第一条消息的一部分和第二条消息全部,
即同一条消息被拆到两个数据包发送了,这种情况就叫做拆包
产生拆包和粘包的原因:
3个前置知识点:
I. tcp是以流动的方式传输数据,传输的最小单位是报文段(Segment)。
II. tcp Header中有个Option标识位,常见的标识叫mss(Max Segment Size),意思是连接层每次传输数据的最大限制(MTU),一般是1500bit,超过这个
数字要分成多个报文段去传输,mss则是最大限制减去Header的长度,就是只是数据包的大小,大约是1460bit,也就是180字节(B)
III. tcp为提高性能,会把要发送的数据先放到网络缓冲区(大小可在程序里设定),等缓冲区满了之后,再将缓冲区中的数据发送到接收方,同理接收方也有缓冲区这样的机制来接收数据。
拆包:应用程序写入缓冲区的消息,大于缓冲区的大小,一次写不完,即一条消息要分到多个数据包来写,就发生的拆包;
或者:进行mss(最大报文长度分段),当tcp报文长度 - Header > mss时,也会发生拆包。
粘包:应用程序一次写入缓冲区的消息小于缓冲区的大小,缓冲区等下一个或多个消息写入,写满之后,发到服务端,即一个数据包里有多条消息,就发生的拆包
或者:接收方未及时读取缓冲区的内容,导到缓冲区有多条消息,就导致粘包
一个缓冲区可以有多个segment,如果segment和缓冲区大小相等,segment里面报文长度也刚好是一条消息,这时候不会发生拆包或粘包。
如何解决拆包的粘包呢?
方法I: 使用带消息头的协议,消息头存储消息开始标识和消息长度,服务端获取到消息头时,解析出消息长度,然后后后读取该消息内容,如:0000000036{"type":"message","content":"hello"}
方法II:设置定长消息,服务端每次读取即定长度为一条消息。报文大小固定长度,不够空格补全,发送和接收方遵循相同的约定,这样即使粘包了通过接收方编程实现获取定长报文也能区分。https://blog.csdn.net/zbw18297786698/article/details/53678323
方法III:设置消息边界,服务端按消息边界从网络流中读取内容。比如:{"type":"message","content":"hello"}\n