tcp

TCP协议通信流程

Posted by ysd on June 17, 2016

  • listen()调用后,对于给定的监听套接口,内核要维护两个队列:
    1. 已由客户发出SYN并到达服务器,服务器正在等待完成相应的TCP三次握手过程,若三路握手完成,该项就移至已完成连接队列
    2. 已完成连接的队列
  • accept()从已完成连接队列返回第一个连接,如果已完成连接队列为空,则阻塞
  • connect()发出SYN_SENT,并阻塞程序,等待应答;收到ACK后返回
    1. 若客户端没收到SYN分节的响应,则返回ETIMEOUT错误;
    2. 若对客户的响应是RST(表示复位),表明服务器上指定端口没有进程与之连接,客户收到RST返回ECONNREFUSED错误
  • 为什么三次握手 为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误 client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。 本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。 于是就向client发出确认报文段,同意建立连接。 假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。 由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。 但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。
  • 由于TCP连接是全双工的,接收到FIN时意味将没有数据再发来,但是还是可以继续发送数据。 因此每个方向都必须单独进行关闭。 这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。 收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。
  • TIME_WAIT
    • 可靠地实现TCP全双工连接的终止: TCP协议在关闭连接的四次握手过程中,最终的ACK是由主动关闭连接的一端(后面统称A端)发出的, 如果这个ACK丢失,对方(后面统称B端)将重发出最终的FIN,因此A端必须维护状态信息(TIME_WAIT)允许它重发最终的ACK。 如果A端不维持TIME_WAIT状态,而是处于CLOSED 状态,那么A端将响应RST分节,B端收到后将此分节解释成一个错误
    • 允许老的重复分节在网络中消逝: TCP分节可能由于路由器异常而“迷途”,在迷途期间,TCP发送端可能因确认超时而重发这个分节, 迷途的分节在路由器修复后也会被送到最终目的地,这个迟到的迷途分节到达时可能会引起问题。 在关闭“前一个连接”之后,马上又重新建立起一个相同的IP和端口之间的“新连接”, “前一个连接”的迷途重复分组在“前一个连接”终止后到达,而被“新连接”收到了。 为了避免这个情况,TCP协议 不允许处于TIME_WAIT状态的连接启动一个新的可用连接,因为TIME_WAIT状态持续2MSL, 就可以保证当成功建立一个新TCP连接的时候,来自旧连接重复分组已经在网络中消逝。