基础
面向字节流的协议传输的是原始的字节数据流,没有内建的消息边界。数据被看作是一个连续的字节流,接收端需要自行解析数据的结构和边界。
字符流:有消息边界,字符流协议通常会有明确的消息边界标识(如换行符),接收端根据这些边界进行数据分割和处理。
特性 | 面向字节流协议 | 面向字符流协议 |
数据处理 | 原始字节流,数据无明确边界 | 处理字符数据,通常有明确的消息边界 |
消息边界 | 无内建消息边界,需由应用层处理 | 通常使用分隔符(如换行符)作为消息边界 |
应用场景 | 适用于需要高效传输任意类型数据的场景 | 适用于文本数据传输,需处理字符编码和字符集 |
协议示例 | TCP、UNIX 域套接字 | HTTP、FTP |
数据类型 | 可以传输任意二进制数据 | 主要用于传输文本数据 |
处理复杂度 | 处理和解析数据的复杂度较高 | 数据处理较为简单,基于文本的处理 |
原因
- 发送端:连续发送消息时,在发送端的操作系统的缓存区上可能把这些数据包合并成一个巨大的数据包一起发送,就造成了粘包的情况
- 接收端:接收消息的时候,无法知道数据的边界,就可能把多个数据包当成一个数据包进行接收
- 数据包过小或者过大也会出现问题,如果发送端发送多个小数据包,由于接收端无法区分边界,所以可能会合并成一个数据包。当发送端发送一个巨大的数据包,TCP就会进行分段,接收端接收的也就不是一个完整的数据包
解决办法
- 消息头:在每个数据包前添加消息头,消息头中包含消息的长度信息。接收端首先读取消息头,确定消息的长度,然后读取完整的消息。
添加分隔符:在数据包之间添加特定的分隔符,如换行符、特殊字符等,接收端根据分隔符来区分消息边界。
- 定义固定长度:协议中定义每个消息的固定长度,接收端可以根据固定长度读取数据。
如果每个消息长度为 100 字节,接收端读取数据时,每 100 字节作为一个完整的消息进行处理。