TCP在发送超过最大分段大小(MSS)的大数据包时是如何组合数据的?

huangapple go评论119阅读模式
英文:

How does TCP combine data when sending a big data packet which is over MSS?

问题

这是一个tcpdump演示。

  • seq 1 - 52001是大数据,超过我的回环MSS(16384)。
  • seq 52001 - 52013是小数据。

TCP如何知道seq 1 - 52001是一个组合的数据块,seq 52001 - 52013是另一个组合的数据块?

以下是我的客户端代码:

  1. func main() {
  2. conn, err := net.Dial("tcp", "127.0.0.1:30000")
  3. if err != nil {
  4. fmt.Println("拨号失败,错误", err)
  5. return
  6. }
  7. defer conn.Close()
  8. msg := ""
  9. for i := 0; i < 2000; i++ {
  10. msg += `你好,你好。你好吗?`
  11. }
  12. conn.Write([]byte(msg))
  13. conn.Write([]byte("演示内容"))
  14. }
英文:

Here is a tcpdump demo.

  • seq 1 - 52001 is big data, over my loopback MSS (16384).
  • seq 52001 - 52013 is small data.

How does TCP know seq 1 - 52001 is a combined data block and seq 52001 - 52013 is another combined data block?

  1. 23:10:00.773752 IP localhost.56006 &gt; localhost.30000: Flags [S], seq 3081455670, win 65535, options [mss 16344,nop,wscale 6,nop,nop,TS val 807676974 ecr 0,sackOK,eol], length 0
  2. 23:10:00.774059 IP localhost.30000 &gt; localhost.56006: Flags [S.], seq 1040822423, ack 3081455671, win 65535, options [mss 16344,nop,wscale 6,nop,nop,TS val 3518795094 ecr 807676974,sackOK,eol], length 0
  3. 23:10:00.774101 IP localhost.56006 &gt; localhost.30000: Flags [.], ack 1, win 6379, options [nop,nop,TS val 807676974 ecr 3518795094], length 0
  4. 23:10:00.774125 IP localhost.30000 &gt; localhost.56006: Flags [.], ack 1, win 6379, options [nop,nop,TS val 3518795094 ecr 807676974], length 0
  5. 23:10:00.783835 IP localhost.56006 &gt; localhost.30000: Flags [.], seq 1:16333, ack 1, win 6379, options [nop,nop,TS val 807676984 ecr 3518795094], length 16332
  6. 23:10:00.783840 IP localhost.56006 &gt; localhost.30000: Flags [.], seq 16333:32665, ack 1, win 6379, options [nop,nop,TS val 807676984 ecr 3518795094], length 16332
  7. 23:10:00.783843 IP localhost.56006 &gt; localhost.30000: Flags [.], seq 32665:48997, ack 1, win 6379, options [nop,nop,TS val 807676984 ecr 3518795094], length 16332
  8. 23:10:00.783847 IP localhost.56006 &gt; localhost.30000: Flags [P.], seq 48997:52001, ack 1, win 6379, options [nop,nop,TS val 807676984 ecr 3518795094], length 3004
  9. 23:10:00.783861 IP localhost.56006 &gt; localhost.30000: Flags [P.], seq 52001:52013, ack 1, win 6379, options [nop,nop,TS val 807676984 ecr 3518795094], length 12
  10. 23:10:00.783874 IP localhost.56006 &gt; localhost.30000: Flags [F.], seq 52013, ack 1, win 6379, options [nop,nop,TS val 807676984 ecr 3518795094], length 0
  11. 23:10:00.784068 IP localhost.30000 &gt; localhost.56006: Flags [.], ack 16333, win 6124, options [nop,nop,TS val 3518795104 ecr 807676984], length 0
  12. 23:10:00.784106 IP localhost.30000 &gt; localhost.56006: Flags [.], ack 32665, win 5869, options [nop,nop,TS val 3518795104 ecr 807676984], length 0
  13. 23:10:00.784110 IP localhost.30000 &gt; localhost.56006: Flags [.], ack 48997, win 5614, options [nop,nop,TS val 3518795104 ecr 807676984], length 0
  14. 23:10:00.784114 IP localhost.30000 &gt; localhost.56006: Flags [.], ack 52001, win 5567, options [nop,nop,TS val 3518795104 ecr 807676984], length 0
  15. 23:10:00.784121 IP localhost.30000 &gt; localhost.56006: Flags [.], ack 52013, win 5567, options [nop,nop,TS val 3518795104 ecr 807676984], length 0
  16. 23:10:00.784139 IP localhost.30000 &gt; localhost.56006: Flags [.], ack 52014, win 5567, options [nop,nop,TS val 3518795104 ecr 807676984], length 0
  17. 23:10:00.798479 IP localhost.30000 &gt; localhost.56006: Flags [F.], seq 1, ack 52014, win 5567, options [nop,nop,TS val 3518795119 ecr 807676984], length 0
  18. 23:10:00.798571 IP localhost.56006 &gt; localhost.30000: Flags [.], ack 2, win 6379, options [nop,nop,TS val 807676999 ecr 3518795119], length 0

Here is my client code:

  1. func main() {
  2. conn, err := net.Dial(&quot;tcp&quot;, &quot;127.0.0.1:30000&quot;)
  3. if err != nil {
  4. fmt.Println(&quot;dial failed, err&quot;, err)
  5. return
  6. }
  7. defer conn.Close()
  8. msg := &quot;&quot;
  9. for i := 0; i &lt; 2000; i++ {
  10. msg += `Hello, Hello. How are you?`
  11. }
  12. conn.Write([]byte(msg))
  13. conn.Write([]byte(&quot;demo content&quot;))
  14. }

答案1

得分: 2

TCP如何知道序列1 - 52001是一个组合数据块,序列52001 - 52013是另一个组合数据块呢?

它并不知道。从TCP的角度来看,这只是一个没有任何内部结构的字节流。任何结构(比如一个“消息”)都需要由应用程序协议添加。

换句话说,你不能期望发送端的单次写入/发送会在接收端产生单次读取/接收。

英文:

> How does TCP know seq 1 - 52001 is a combined data block and seq 52001 - 52013 is another combined data block?

It doesn't. From the perspective of TCP this is only a byte stream without any internal structure. Any structure (like a "message") needs to be added by the application protocol.

Or in other words: you cannot expect that a single write/send in the sender will result in a single read/recv in the recpient.

huangapple
  • 本文由 发表于 2023年7月23日 23:19:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76749002.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定