思考两个问题:
1.传输控制,到底控制了什么?
2.如何控制的?
1 TCP的三个关键特征
面向连接:
面向连接意味着两个TCP应用(客户端,服务器)在交换数据之前必须先建立连接。就像是打电话一样,先拨号振铃,等待对方摘机说“喂”,然后才说明是谁。
建立连接的过程也叫做三次握手,使用SYN同步信号,以及应答ACK来实现握手。确保在交换数据之前,双方都处于正常的环境中。
可靠性:
可靠性意味着交换的数据不能出错,稳定可靠。其实现的方式有:
1.TCP数据分割成长度合适的数据段,传递给IP层,数据段称为报文段或段。
2.当TCP发送一个段后,启动一个定时器,并等待对方的应答。若不能及时的收到,则重传。该策略也就是超时重传。
3.TCP将验证校验和,若有误,则丢弃。
4.TCP可控制传输的流量,可通过接收方的通告窗口,来控制发送方的发送数据量。达到收发匹配,防止接收方的缓存溢出。
以上方式均是可靠性的体现。
字节流:
传输的数据均是一个一个的字节,TCP并不对字节流的内容作任何解释,不管是二进制,还是文本,或是其他。关于字节流的解释,是应用层所干的事,比如telnet,HTTP等。
这样的处理方式,是一种高度抽象的方式,提取了所有数据的共性---字节。
就像linux中的一切皆文件。
2 TCP的帧格式
TCP首部的数据长度,一般是20字节。
- 来源连接端口:识别发送连接端口号(0~65535)
- 目的连接端口:识别接收连接端口号(0~65535)
- 序列号
- 如果含有同步化(SYN),则此为最初的序列号,用于建立连接的握手消息
- 如果没有同步化(SYN),则此为第一个数据字节的序列码。
- 确认号(ack):期望收到的数据的开始序列号。也即已经收到的数据的字节长度加1。
- 数据偏移:以4字节为单位计算出的数据段开始地址的偏移值。
- 保留:须置0
- 标志符
- NS—ECN-nonce。ECN显式拥塞通知(Explicit Congestion Notification)是对TCP的扩展,定义于RFC 3168(2001)。ECN允许拥塞控制的端对端通知而避免丢包。ECN为一项可选功能,如果底层网络设施支持,则可能被启用ECN的两个端点使用。在ECN成功协商的情况下,ECN感知路由器可以在IP头中设置一个标记来代替丢弃数据包,以标明阻塞即将发生。数据包的接收端回应发送端的表示,降低其传输速率,就如同在往常中检测到包丢失那样。
- CWR—Congestion Window Reduced。
- ECE—ECN-Echo有两种意思,取决于SYN标志的值。
- URG—为1表示高优先级数据包,紧急指针字段有效。
- ACK—为1表示确认号字段有效。
- PSH—为1表示是带有PUSH标志的数据,指示接收方应该尽快将这个报文段交给应用层而不用等待缓冲区装满。
- RST—为1表示出现严重差错。可能需要重新创建TCP连接。还可以用于拒绝非法的报文段和拒绝连接请求。
- SYN—为1表示这是连接请求或是连接接受请求,用于创建连接和使顺序号同步。
- FIN—为1表示发送方没有数据要传输了,要求释放连接。
- 窗口(WIN):表示从确认号开始,本报文的发送方可以发送的字节数,即接收窗口大小。用于流量控制。
- 校验和:对整个的TCP报文段,包括TCP头部和TCP数据,以16位字进行计算所得。这是一个强制性的字段。
- 紧急指针(16位长)—本报文段中的紧急数据的最后一个字节的序号。
3 代码分析
在NuttX操作系统中,使用的tcp/ip协议栈为 uIP。
TCP首部的数据结构:对应于上面的帧格式
/* TCP header */
struct tcp_hdr_s
{
uint16_t srcport;
uint16_t destport;
uint8_t seqno[4];
uint8_t ackno[4];
uint8_t tcpoffset;
uint8_t flags;
uint8_t wnd[2];
uint16_t tcpchksum;
uint8_t urgp[2];
uint8_t optdata[4];
};
帧格式中的标志位:其中NS, CWR, ECE未实现
/* TCP definitions */
#define TCP_FIN 0x01
#define TCP_SYN 0x02
#define TCP_RST 0x04
#define TCP_PSH 0x08
#define TCP_ACK 0x10
#define TCP_URG 0x20
#define TCP_CTL 0x3f
4 总结
so,传输控制,到底控制了什么?
控制了数据传输的可靠性,稳定性。通过连接与断开,分段编序号,超时重传,拥塞控制,流量控制等一系列措施来实现可靠的交换数据。