← Back to blog

不背八股!!!为什么说TCP是基于字节流的?

面试网络

不背八股!!!为什么说TCP是基于字节流的?

什么是基于字节流?

我们都知道TCP的一大特点就是基于字节流 ,从字面意思上来说,TCP在传输报文的时候并不是一个个报文传输的,而是一个个字节 传输的。

因为TCP无消息边界的TCP不保留消息的边界,也不提供消息开始和结束的标记,发送方将数据按照字节流进行发送,接收方需要根据应用层协议的规定来划分消息。

并且TCP提供了可靠的数据流传输,接收方无法确定消息边界,并且消息以流的形式进行传输,发送方可以把这个报文的一部分先传输过去,剩下的部分和下一次要传输的内容一起传输过去,这也是会造成拆包粘包 的原因之一。

为什么TCP基于字节流?

那么为什么TCP可以用这种方式进行数据的传输呢?

其实TCP基于字节流这个与TCP的可靠性又分不开,因为TCP是可靠的,所以可以面向字节流进行传输,因为UDP是不可靠的,所以UDP只能单个报文进行传输。

举个例子,假如我们想要发送一大段视频给其他人。

那么这个视频最后的传输依旧是一大串0101的字节码,假如其中的一段是这样的,每一行是一个报文

那么因为TCP是可靠的,所以它知道自己无论如何发送,最终对方收到的都是可靠的报文,何为可靠?

不错误、不重复、不丢失、按序 ,这个时候它就没有必要追求一个个报文发送,而是考虑到IO、缓冲区、网络状况等因素,追求效率的最大化。如果某一次发送的数据丢失或者失败,那么重传即可,并不会影响到其他的数据。

所以TCP可能按照下面几种格式进行发送

为什么UDP基于报文?

也是一样的道理,因为UDP不可靠,所以它只能一个报文一个报文传输,这样在传输失败的时候,仅需进行一个报文的重传,而不需要重传一大段数据。

想一想,如果UDP不可靠,但是又是基于字节流的发送,那么会出现什么问题?

当一次发送的数据因为过大而失败时,不可靠的UDP会不断重试这个过程,但是无法确保这段数据重传成功,会对其他的数据造成影响。 但是有可能在整个数据都发送完毕的时候依旧没有重试成功,这时候接受方收到的数据就是不完整的,轻则丢帧丢数据,重则整个视频都无法打开。

所以UDP的发送格式只能按照下列格式,一个报文一个报文发送。

TCP粘包

粘包是指在数据传输过程中,接收方收到的数据和发送方的逐个报文并不完全一致,而是”粘”在一起的。

代码示例

服务端代码如下 [code] func main() { readTimes := 100 listener, err := net.Listen(“tcp”, “127.0.0.1:10211”) if err != nil { log.Fatal(“tcp listen failed, err:”, err) return } defer listener.Close() for i := 0; i < readTimes; i++ { conn, err := listener.Accept() if err != nil { fmt.Println(“accept msg failed,err:”, err) continue } readMsg(conn) time.Sleep(10 * time.Millisecond) } return }

func readMsg(conn net.Conn) {
	defer conn.Close()
	msg := make([]byte, 100)
	for {
		cnt, err := conn.Read(msg)
		if err == io.EOF {
			fmt.Println("finish read")
			return
		}
		if err != nil {
			fmt.Println("read msg failed, err:", err)
			break
		}
		recvMsg := string(msg[:cnt])
		fmt.Println("receive msg:", recvMsg)
	}
}

[/code]

客户端代码如下 [code] func main() { const sendTimes = 100 conn, err := net.Dial(“tcp”, “127.0.0.1:10211”) if err != nil { log.Fatal(“dial tcp failed, err:”, err) return } defer conn.Close() for i := 0; i < sendTimes; i++ { msg := “welcome to follow blogger anneshaertrecord” conn.Write([]byte(msg)) } return } [/code]

最终效果 [code] receive msg: welcome to follow blogger anneshaertrecord receive msg: welcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follo receive msg: w blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger annesh receive msg: aertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcom receive msg: e to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blog receive msg: ger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertre receive msg: cordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to f receive msg: ollow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger an receive msg: neshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwe receive msg: lcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow receive msg: blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshae receive msg: rtrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome receive msg: to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogge receive msg: r anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertreco receive msg: rdwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to fol receive msg: low blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anne receive msg: shaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelc receive msg: ome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow bl receive msg: ogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaert receive msg: recordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to receive msg: follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger receive msg: anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecord receive msg: welcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follo receive msg: w blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger annesh receive msg: aertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcom receive msg: e to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blog receive msg: ger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertre receive msg: cordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to f receive msg: ollow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger an receive msg: neshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwe receive msg: lcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow receive msg: blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshae receive msg: rtrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome receive msg: to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogge receive msg: r anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertreco receive msg: rdwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to fol receive msg: low blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anne receive msg: shaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelc receive msg: ome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow bl receive msg: ogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaert receive msg: recordwelcome to follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to receive msg: follow blogger anneshaertrecordwelcome to follow blogger anneshaertrecordwelcome to follow blogger receive msg: anneshaertrecordwelcome to follow blogger anneshaertrecord finish read [/code]

可以很明显的看到,并不是每一条消息都为welcome to follow blogger anneshaertrecord,有很多消息”粘”在一起了。

为什么会出现TCP粘包?

有很多导致TCP粘包出现的原因,前面我们提到过的流式传输 以及无消息边界 是最主要的原因。除此之外还有一些其他层面原因导致TCP粘包。

  • Nagle算法:这是一种优化TCP效率的算法,通过延迟小数据包的发送,将它们合并成一个较大的数据包,从而提高效率和网络利用率。
  • 接收方缓冲区限制:当发送方连续发送多个数据包,而接收方的缓冲区大小不足以及时处理这些数据包,也会导致粘包。
  • 网络延迟或者拥塞:数据包可能乱序到达,需要在接收方缓冲区重新拼装。

如何解决TCP粘包?

1.消息边界

通过给消息的不同部分设置分隔符,来实现消息边界的确立,这样接收方就能知道一条数据报应该在哪里结束。比如HTTP报文其实就是通过在不同部分设置换行来进行边界的确立的。

**2.定长消息
** 消息的长度是固定的,如果一条数据报超过这个长度,则进行拆分发送,这种方式不灵活,并且一个大的数据报可能需要拆分多次,效率低。

3.头部字段

在消息头部添加一个字段,用于标识本条消息的长度。接收方首先读取长度字段,然后根据长度读取相应字节数的数据,这样来确保每条消息都能够被正确地分割。

结语

本文向大家介绍了TCP为什么是基于字节流的,以及TCP粘包相关内容。创作不易,如果有收获欢迎点赞、评论、收藏 ,您的支持就是我最大的动力。