TCP协议(0)
TCP协议的定义
TCP是面向连接的通信协议,通过3次握手建立连接,通讯完成要拆除连接,由于TCP是面向连接的,所以只能用于端到端的通信。TCP提供的是可靠的数据流服务。在DNS服务中,像发送和接受域名数据库是使用的TCP协议,而单个主机信息的传输则是使用的UDP。
TCP的服务
TCP通过下列方式来提供可靠性:
1.应用程序被分割成TCP认为最适合发送的数据块(这与UDP完全不同,UDP的数据报不会被分割);
2.当TCP发出一个段后,它启动一个定时器,等到目的端确认收到了这个报文段。如果不能及时收到确认,将重发这个报文段(超时重传);
3.当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送的,通常会推迟几分之1秒(数据捎带ACK);
4.TCP将保持它首部和数据的检验和。如果收到段的检验和有差错,TCP将丢弃这个报文段和不确认收到此报文段;
5.由于TCP报文段是作为IP数据报来传输的,所以有可能会失序,所以TCP报文段的到达也可能会失序。如果必要,TCP将对收到的数据进行重新排序;
6.既然IP数据包会发生重复,TCP的接受端必须丢弃重复的数据;
7.TCP还能提供流量控制(滑动窗口),TCP连接的每一方都有固定大小的缓冲空间。TCP的接受端只允许另一端发送接受端缓冲区所能接纳的数据。这能防止较块主机致使较慢主机的缓冲区溢出;
TCP的三次握手
1.请求端发送一个SYN段指明客户打算连接的服务器端口,以及初始序号;
2.服务器发回包含服务器的初始序号的SYN报文段作为应答。同时,将确认序号设置为客户的ISN加1以对客户的SYN报文段进行确认。一个SYN将占用一个序号;
3.客户必须将确认序号设置为服务器的ISN加1以对服务器的SYN报文段进行确认。
为什么是三次握手?
在谢希仁的《计算机网络》中解释得就比较好了,如果我们在3之后服务器又对客户发送的确认数据报进行确认,那么就会进行无限的循环中,又或者说其实这一步是没有必要的。那么为什么我们不用2次握手呢?这是因为如果只是两次握手的话,当服务器端发送对客户端的SYN的确认之后建立就形成了,但是存在这样的情况:客户端发送的一个SYN数据报文经过了一段存在延时的网络,导致很晚才到服务器端,而客户端已经是重新发送的了,所以此时这个报文应该是无效的。但是如果只有两次握手,那么这个超时的SYN到达服务器端,服务器端发送确认,建立就形成了。这样会造成资源的浪费,如果用三次握手,当服务器发送确认之后,客户端不对服务器的确认进行确认,服务器就会知道这个SYN请求是已经过期的了,那么就能很好地避免这种情况的发生了。
TCP的四次挥手
建立一个连接需要三次握手,而终止一个连接要经过4次握手。这是由TCP的半关闭造成的,TCP是一种全双工通信,所以关闭连接必须要在每个方向上单独进行关闭。收到一个FIN只意味着在这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。
状态解释:
LISTEN:这种状态表示正在等待连接;一般服务器端会处理这种状态;
SYN_SEND:即表示客户端发起请求连接,发送了SYN数据报之后处于这种状态;
SYN_RCVD:即表示服务器端已经接收到了客户端发起的连接请求,并且同意建立连接,所以会发送一个带ack的SYN给客户端;
ESTABLISHED:表示接受到了对应的ACK,此时该方向上的连接已经建立。
FIN_WAIT_1:是指一方主动发起关闭连接的请求,当向对方发送了FIN之后,进入此状态;
FIN_WAIT_2:是指主动发起关闭连接请求的一方现在收到了对方发送的ack报文,则进入此状态;
CLOSE_WAIT:在此状态时,表明对方已经发送了FIN,而且已经回了ack报文给对方,此时,被动关闭一方处于等待关闭的状态;
LAST_ACK:此状态代表正在等待主动关闭方发送最后一个ACK,之后便会进入CLOSED状态;
TIME_WAIT:也称为2MSL(Maximum Segment Lifetime)等待状态,表明主动关闭方再等待2MSL后便会进入CLOSED
CLOSED:表明当前已经处于断开连接的状态。
问题1:FIN与ACK是否可以一起发送呢?如果可以,那不就是3次挥手了么?
其实从TCP的首部,我们就可以知道FIN和ACK其实都是一个标志位,所以说理论上它们是可以被同时被发送的(与其这么说,倒不如说我们只需要发送一个带了ACK和FIN标志位都为1的数据报文即可让主动关闭方从FIN_WAIT_1到TIME_WAIT状态)。但是一般来说,被动关闭方还是在主动关闭方发起关闭请求时,还是需要继续发送一些数据的。所以说一般还是会先只发送ack,而不是将FIN与ACK一起发送。所以一般还是称为四次挥手。
问题2:2MSL是什么?
《TCP/IP协议卷详解1》中说到RFC 793 [Postel 1981c]指出MSL为2分钟,然后,现实中的常用值是30秒,1分钟或者2分钟,那么2MSL就是2*MSL咯。
问题3:那么TIME_WAIT有什么用呢?
1)可靠地实现TCP全双工连接的终止
TCP协议在关闭连接的四次握手过程中,最终的ACK是由主动关闭连接的一端(后面统称A端)发出的,如果这个ACK丢失,对方(后面统称B端)将重发出最终的FIN,因此A端必须维护状态信息(TIME_WAIT)允许它重发最终的ACK。如果A端不维持TIME_WAIT状态,而是处于CLOSED 状态,那么A端将响应RST分节,B端收到后将此分节解释成一个错误(在java中会抛出connection reset的SocketException)。
因而,要实现TCP全双工连接的正常终止,必须处理终止过程中四个分节任何一个分节的丢失情况,主动关闭连接的A端必须维持TIME_WAIT状态 。
2)允许老的重复分节在网络中消逝
TCP分节可能由于路由器异常而“迷途”,在迷途期间,TCP发送端可能因确认超时而重发这个分节,迷途的分节在路由器修复后也会被送到最终目的地,这个迟到的迷途分节到达时可能会引起问题。在关闭“前一个连接”之后,马上又重新建立起一个相同的IP和端口之间的“新连接”,“前一个连接”的迷途重复分组在“前一个连接”终止后到达,而被“新连接”收到了。为了避免这个情况,TCP协议不允许处于TIME_WAIT状态的连接启动一个新的可用连接,因为TIME_WAIT状态持续2MSL,就可以保证当成功建立一个新TCP连接的时候,来自旧连接重复分组已经在网络中消逝。
Nagle算法
Nagle算法要求一个TCP连接上最多只能有一个未被确认的未完成的小分组,在该分组的确认到达之前不能发送其他的小分组。相反,TCP收集这些少量的分组,并在确认到来时以一个分组的方式发送出去。
优点:该算法是自适应的,确认到达得越快,数据也就发送得越快,而在希望减少微分组数目得低速广域网上,则会发送更少的分组。
缺点:在某个连接上,要求必须无时延发送TCP的报文段,但是Nagle算法会导致报文的延迟发送,所以在实现Nagle算法时,必须为应用提供关闭该算法的方法。