TCP的可靠传输首先是建立在可靠的连接建立与关闭之上,这一块包含以下要点:
- TCP三次握手建立连接
- TCP半关闭
- TCP的状态变迁
- TCP服务端监听和处理设计
TCP三次握手建立连接
TCP为了通信双方确认建立起连接,设计了三次握手的策略,三次握手的过程如下:
1) 请求端发送一个SYN段指明客户打算连接的服务器的端口,以及初始序号(ISN)。
2) 服务器发回包含服务器的初始序号的SYN报文段作为应答。同时,将确认序号设置为客户的ISN加1以对客户的SYN报文段进行确认。一个SYN将占用一个序号。
3) 客户必须将确认序号设置为服务器的ISN加1以对服务器的SYN报文段进行确认
举一个实例:
为什么是三次握手?
对于这个问题,网络编程中的一个经典的规则也许能给一些提示:别人告诉你成功了那一定是成功了,没告诉你成功不一定是没成功。因此,如果是设计成两次握手,就有可能是被连接方第一次发出ack消息后,就处于成功建立连接的状态,但这条消息丢失了,主动连接方因为没有收到这个ack消息会认为建立连接失败,也许会放弃连接或启动新的连接,但被连接方会一直监听那个它误认为成功的连接。采用三次握手,前两次握手任何一次失败都会导致连接双方都处于未连接状态,第三次失败只会导致连接方处于成功状态,但做主动连接方,肯定会在连接不久后通过这个连接发送数据,这样就可以利用这个机制做进一步的容错。
通过tcpdump工具能很清晰地看到三次握手的过程,先在主机B(itbu_qa17)上打开tcpdump监控
/usr/local/sbin/tcpdump port 80 and host 10.19.14.1
然后主机A(10.19.14.1) telnet到主机B,tcpdump监控结果如下:
TCP半关闭
TCP半关闭时TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。因此,连接关闭的过程需要连接双方都要发起关闭连接的消息,示意图如下所示:
为什么要设计成半关闭?
设计成半关闭主要是存在无需发送数据,只需接收数据的需求,并且可以通过发起单方面的关闭请求标志已发送数据完成。如果没有半关闭的需求,就得建立两个连接。
通过tcpdump工具能很清晰地看到三次握手的过程,主机A(10.19.14.1) telnet到主机B,然后在主机B(itbu_qa17)上打开tcpdump监控
/usr/local/sbin/tcpdump port 80 and host 10.19.14.1
然后主机A关闭telnet,tcpdump监控结果如下:
TCP的状态变迁
连接双方从新建连接到建立连接再到关闭连接,会经历一些状态,这些状态在分析问题时非常重要,状态变迁全景图如下所示:
就连接双方的建立连接和关闭连接过程来看,状态变迁序列图如下所示:
TCP服务端监听和处理设计
TCP服务端一般设计为连接建立后一个进程监听端口,当一个新的连接请求到达服务器时,服务器接受这个请求,并调用一个新进程来处理这个新的客户请求。以telnet为例,使用netstat查看服务端监听状态为LISTEN,如下图所示:
当有客户端telnet过来时,监听进程会起另外的进程来处理,如下图所示: