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 字节端数据,可能会被拆分成多个报文发送,如下图:
- 1、2、3 字节已经通过发送到
Server
应用程序 - 4、5、6、7 字节在
Server
的TCP栈
中 - 8、9 字节还在网络中传输
- 10、11、12、13 字节刚从
IP层
传出,现在可能在数据链路层 - 14、15、16、17、18 字节在
Client
的TCP栈
中 - 19、20、21、22 字节在
Client
的应用层中
如果不分成层的活可能会出现 2 个问题
- 数据太大、IP 层会分层
- 不进行流控
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