作者 | 王磊
来源 | Java中文社群(ID:javacn666)
大家好,我是跃哥。跃哥之前使用过Socket,同时在前面的Java学习之路上,也提到过Socket通信可以很好的作为练手项目进行Java 学习。但是,Socket 学起来简单,用起来的时候,不免会遇到各种各样的问题。
粘包就是一个很烦躁的问题,是吧?简短的数据传输可能没什么问题,但是遇到冗长的数据传输,你在使用的时候会有疑问:咦?我的数据怎么不全呀?怎么这么奇怪?那我们就来探索下,王哥给我们的方案,来搞懂粘包问题吧。
在 Java 语言中,传统的 Socket 编程分为两种实现方式,这两种实现方式也对应着两种不同的传输层协议:TCP 协议和 UDP 协议,但作为互联网中最常用的传输层协议 TCP,在使用时却会导致粘包和半包问题,于是为了彻底的解决此问题,便诞生了此篇文章。
什么是 TCP 协议?
TCP 全称是 Transmission Control Protocol(传输控制协议),它由 IETF 的 RFC 793 定义,是一种面向连接的点对点的传输层通信协议。
TCP 通过使用序列号和确认消息,从发送节点提供有关传输到目标节点的数据包的传递的信息。TCP 确保数据的可靠性,端到端传递,重新排序和重传,直到达到超时条件或接收到数据包的确认为止。
TCP 是 Internet 上最常用的协议,它也是实现 HTTP(HTTP 1.0/HTTP 2.0)通讯的基础,当我们在浏览器中请求网页时,计算机会将 TCP 数据包发送到 Web 服务器的地址,要求它将网页返还给我们,Web 服务器通过发送 TCP 数据包流进行响应,然后浏览器将这些数据包缝合在一起以形成网页。
TCP 的全部意义在于它的可靠性,它通过对数据包编号来对其进行排序,而且它会通过让服务器将响应发送回浏览器说“已收到”来进行错误检查,因此在传输过程中不会丢失或破坏任何数据。
目前市场上主流的 HTTP 协议使用的版本是 HTTP/1.1,如下图所示:
什么是粘包和半包问题?
粘包问题是指当发送两条消息时,比如发送了 ABC 和 DEF,但另一端接收到的却是 ABCD,像这种一次性读取了两条数据的情况就叫做粘包(正常情况应该是一条一条读取的)。
半包问题是指,当发送的消息是 ABC 时,另一端却接收到的是 AB 和 C 两条信息,像这种情况就叫做半包。
为什么会有粘包和半包问题?
这是因为 TCP 是面向连接的传输协议,TCP 传输的数据是以流的形式,而流数据是没有明确的开始结尾边界,所以 TCP 也没办法判断哪一段流属于一个消息。