TCP 是一个面向字节流的协议,它不限制应用层传输消息的长度,但实际上在 TCP 之下的数据层和网络层由于发送和接收报文使用的内存是有限的,所以它们一定会限制报文的长度。TCP 需要讲从 应用层接收到的任意长度的字节流,切分成许多报文段,那么拆分层报文段的依据是什么呢。

TCP 编程案例

Code

// 客户端
func Client() {
	// 建立联链接
	conn, err := net.Dial("tcp", address)
	defer conn.Close()
	// 发送数据
	send_msg := []byte("hello")
	n, err = conn.Write([]byte(toWrite))
	// 接收数据
	receive_msg := make([]byte, SERVER_RECV_LEN)
	n, err = conn.Read(msg)
}

// 服务端
func Server() {
	// 监听端口
	listener, err := net.Listen("tcp", address)
	defer listener.Close()

	for {
		conn, err := listener.Accept()
		defer conn.Close()
		for {
			// 接收数据
			receive := make([]byte, SERVER_RECV_LEN)
			_, err = conn.Read(data)
			fmt.Println("Received:", string(data))
			// 回复数据
			reply = "hello" + receive
			_, err = conn.Write([]byte(reply))
			fmt.Println("Send:", reply)
		}
	}
}

系统原理

TCP 流与报文段

应用程序一次发送 22 字节端数据,可能会被拆分成多个报文发送,如下图:

TCP stream segment

  • 1、2、3 字节已经通过发送到Server应用程序
  • 4、5、6、7 字节在ServerTCP栈
  • 8、9 字节还在网络中传输
  • 10、11、12、13 字节刚从IP层传出,现在可能在数据链路层
  • 14、15、16、17、18 字节在ClientTCP栈
  • 19、20、21、22 字节在 Client 的应用层中

如果不分成层的活可能会出现 2 个问题

  • 数据太大、IP 层会分层
  • 不进行流控

TCP wireshark mss

MSS 概念

MSS(Max Segment Size)

  • 定义:仅指 TCP 承载数据,不包含 TCP 头部的大小,参见 RFC879
  • MSS 选择目的
    • 尽量每个 Segment 报文段携带更多的数据,以减少头部空间占用比率
    • 防止 Segment 被某个设备的 IP 层基于 MTU 拆分
  • 默认 MSS:536 字节(默认 MTU576 字节,20 字节 IP 头部,20 字节 TCP 头部)
  • 握手阶段协商 MSS
  • MSS 分类
    • 发送方最大报文段 SMSS:SENDER MAXIMUM SEGMENT SIZE
    • 接收方最大报文段 RMSS:RECEIVER MAXIMUM SEGMENT SIZE