TCP
https://www.cnblogs.com/xrq730/p/6910719.html
TCP三次握手和短连接优化: http://www.lihongkun.com/network/tcp_handshake_and_short_connection/
TCP协议头部格式
这张图把TCP协议头部格式的每部分都描述得比较清楚:
- Source Port与Destination Port表示源端口与目标端口,各占据2个字节
- Sequence Number表示顺序号,占4个字节,每一个字节都有一个序号,连接建立时发送方将初始序号填写到第一个发送的TCP段序号中
- Acknowledgment Number表示应答号,占4个字节,是期望收到对方下次发送的数据的第一个字节的序号,也就是期望收到的下一个报文段的首部中的序号
- Offset表示数据偏移量,占4位,表示数据开始的地方离TCP段的起始处有多远,实际上就是TCP段首部的长度
- Reserved表示保留位,占4位,全为0,为了将来定义新的用途保留
- C表示CWR,占1位,拥塞窗口减少标识,发送方设置,用于表明它收到了ECE标识的TCP包,发送端通过降低发送窗口的大小来降低速率
- E表示ECN,占1位,用于TCP3次握手时表示一个TCP端是具备ECN功能的
- U表示URG,占1位,该标志位表示紧急标识有效
- A表示ACK,占1位,表示Acknowledgment Number字段有效,这是一个确认的TCP包,0表示不是确认包
- P表示PSH,占1位,该标志位设置时一般表示发送端缓存中已经没有待发送的数据,接收端不将该数据进行队列处理
- R表示RST,占1位,用于复位相应的TCP链接
- S表示SYN,占1位,该标志仅在三次握手建立TCP连接时有效
- F表示FIN,占1位,带有该标志位的数据包用来结束一个TCP会话,但对应端口仍处于开放状态,准备接收后续数据
- Window表示窗口,占2个字节,表示报文段发送方期望收到的字节数,换句话说用于表示接收端还有多少空间剩余,用于控制TCP流量
- Checksum表示校验和,占2个字节,发送端基于数据内容计算一个数值,接收端要与发送端数值结果完全一样,才能证明数据的有效性,接收端校验失败会直接丢掉这个数据包
- Urgent Pointer表示紧急指针,占2个字节,指向后面优先数据的字节,只有在URG标识设置了才有效
- TCP Options表示TCP选项,长度不定,但必须是32bits的整数倍,常见的选项包括MSS、SACK、Timestamp等
从图上我们可以看到,TCP头部的固定大小为20个字节,不过由于有可选字段,实际上TCP头部的大小有可能超过20字节。
TCP三次握手
TCP三次握手是TCP一个比较重点的内容,来学习一下。
TCP三次握手其实就是TCP连接建立的过程,三次握手的目的是同步连接双方的序列号和确认号并交换TCP窗口大小信息。下面是TCP三次握手的流程图:
画得很清晰,可惜不是我画的。整个流程为:
- 客户端主动打开,发送连接请求报文段,将SYN标识位置为1,Sequence Number置为x(TCP规定SYN=1时不能携带数据,x为随机产生的一个值),然后进入SYN_SEND状态
- 服务器收到SYN报文段进行确认,将SYN标识位置为1,ACK置为1,Sequence Number置为y,Acknowledgment Number置为x+1,然后进入SYN_RECV状态,这个状态被称为半连接状态
- 客户端再进行一次确认,将ACK置为1(此时不用SYN),Sequence Number置为x+1,Acknowledgment Number置为y+1发向服务器,最后客户端与服务器都进入ESTABLISHED状态
为什么在第3步中客户端还要再进行一次确认呢?这主要是为了防止已经失效的连接请求报文段突然又传回到服务端而产生错误的场景:
所谓"已失效的连接请求报文段"是这样产生的。正常来说,客户端发出连接请求,但因为连接请求报文丢失而未收到确认。于是客户端再次发出一次连接请求,后来收到了确认,建立了连接。数据传输完毕后,释放了连接,客户端一共发送了两个连接请求报文段,其中第一个丢失,第二个到达了服务端,没有"已失效的连接请求报文段"。 现在假定一种异常情况,即客户端发出的第一个连接请求报文段并没有丢失,只是在某些网络节点长时间滞留了,以至于延误到连接释放以后的某个时间点才到达服务端。本来这个连接请求已经失效了,但是服务端收到此失效的连接请求报文段后,就误认为这是客户端又发出了一次新的连接请求。于是服务端又向客户端发出请求报文段,同意建立连接。假定不采用三次握手,那么只要服务端发出确认,连接就建立了。
由于现在客户端并没有发出连接建立的请求,因此不会理会服务端的确认,也不会向服务端发送数据,但是服务端却以为新的传输连接已经建立了,并一直等待客户端发来数据,这样服务端的许多资源就这样白白浪费了。
采用三次握手的办法可以防止上述现象的发生。比如在上述的场景下,客户端不向服务端的发出确认请求,服务端由于收不到确认,就知道客户端并没有要求建立连接。