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

分类: 365网址经常打不开 时间: 2026-02-15 12:03:42 作者: admin 阅读: 7332
不背八股!!!为什么说TCP是基于字节流的?

什么是基于字节流?

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

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

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

为什么TCP基于字节流?

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

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

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

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

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

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

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

为什么UDP基于报文?

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

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

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

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

TCP粘包

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

代码示例

服务端代码如下

go

复制代码

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)

}

}

客户端代码如下

go

复制代码

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

}

最终效果

yaml

复制代码

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

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

为什么会出现TCP粘包?

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

Nagle算法:这是一种优化TCP效率的算法,通过延迟小数据包的发送,将它们合并成一个较大的数据包,从而提高效率和网络利用率。

接收方缓冲区限制:当发送方连续发送多个数据包,而接收方的缓冲区大小不足以及时处理这些数据包,也会导致粘包。

网络延迟或者拥塞:数据包可能乱序到达,需要在接收方缓冲区重新拼装。

如何解决TCP粘包?

1.消息边界

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

2.定长消息

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

3.头部字段

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

结语

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

相关推荐