tcp是流的一些思考--拆包和粘包

假设应用层协议是http

我从浏览器中访问了一个网站,网站服务器给我发了200k的数据。建立连接的时候,通告的MSS是50k,所以为了防止ip层分片,tcp每次只会发送50k的数据,一共发了4个tcp数据包。如果我又访问了另一个网站,这个网站给我发了100k的数据,这次tcp会发出2个包,问题是,客户端收到6个包,怎么知道前4个包是一个页面,后两个是一个页面。既然是tcp将这些包分开了,那tcp会将这些包重组吗,它送给应用层的是什么?

这是我自己想的一个场景,正式一点讲的话,这个现象叫拆包

我们再考虑一个问题。

tcp中有一个negal算法,用途是这样的:通信两端有很多小的数据包要发送,虽然传送的数据很少,但是流程一点没少,也需要tcp的各种确认,校验。这样小的数据包如果很多,会造成网络资源很大的浪费,negal算法做了这样一件事,当来了一个很小的数据包,我不急于发送这个包,而是等来了更多的包,将这些小包组合成大包之后一并发送,不就提高了网络传输的效率的嘛。这个想法收到了很好的效果,但是我们想一下,如果是分属于两个不同页面的包,被合并在了一起,那客户那边如何区分它们呢?

这就是粘包问题。

从粘包问题我们更可以看出为什么tcp被称为流协议,因为它就跟水流一样,是没有边界的,没有消息的边界保护机制,所以tcp只有流的概念,没有包的概念。

我们还需要有两个概念

  • 长连接: Client方与Server方先建立通讯连接,连接建立后不断开, 然后再进行报文发送和接收。
  • 短连接:Client方与Server每进行一次报文收发交易时才进行通讯连接,交易完毕后立即断开连接。此种方式常用于一点对多点 通讯,比如多个Client连接一个Server.

下面我们揭晓答案:

  1. 我想象的关于粘包的场景是不对的,http连接是短连接,请求之后,收到回答,立马断开连接,不会出现粘包。
  2. 拆包现象是有可能存在的

##处理拆包
既然拆包现象可能存在,如果遇到了,那么该如何处理呢?这里提供两种方法

  1. 通过包头+包长+包体的协议形式,当服务器端获取到指定的包长时才说明获取完整。
  2. 指定包的结束标识,这样当我们获取到指定的标识时,说明包获取完整。

##处理粘包
我们从上面的分析看到,虽然像http这样的短连接协议不会出现粘包的现象,但是一旦建立了长连接,粘包还是有可能会发生的。

网上的处理方法有很多,这里不列举了,但大家看这些处理方法,都会发现,这些方法并不好,都会做一些牺牲。比如禁用negal算法,就是以网络性能作为牺牲。