计算机网络——TCP

IP协议只是让两台主机连接起来,数据只是到了主机这个层面,数据真正的通信的主体是主机中的进程

TCP连接是更进一步的连接,是端对端的通信、应用进程之间的通信

首先需要了解TCP报文的一些字段的含义,这对后面的理解非常关键

  • SYN:建立连接
  • ACK:响应
  • FIN:关闭连接
  • PSH:有DATA数据传输
  • RST:连接重置

这几个字段都可以组合使用,例如:单独SYN为1时,表示请求建立连接;SYN和ACK都为1时,表示发送连接请求之后的响应;关闭连接的FIN的组合同理

TCP建立连接三次握手过程

TCP服务器进程建立TCB传输控制块(被动打开),准备接收客户进程的连接请求,此时服务器进入LISTEN监听状态

第一次:TCP客户进程建立TCB传输控制块(主动打开),向服务器进程发送连接请求报文。报文首部包含一个同步位SYN=1,并选择一个初始序列号seq=x,此时TCP客户端进程进入SYN-SENT同步已发送状态

第二次:TCP服务器进程接收到请求报文后,如果同意连接,就发送确认报文。报文首部包含同步位SYN=1,ACK=1,确认号ack=x+1,自己也要初始化一个序列号seq=y,此时服务器进入SYN-RCVD同步收到状态,之所以自己还要发送一个序列号,这是规定

第三次:客户端进程接收到确认报文后,发送确认报文给服务器进程ACK=1,序列号seq=x+1,确认号ack=y+1

连接确立,客户端进程进入ESTABILISH已建立连接状态,双方可以开始通信

假设就执行的是两次握手的流程,客户端进程发送请求,服务器端进程接收后确认,连接就确立。那么假如客户端进程向服务器端进程发送一条请求,由于各种原因,请求很慢才到达服务器端进程,客户端进程以为服务器端接收不到,又重新发了一次,服务器端接收到后确认建立连接,这次连接就算完成了;但是第一次发送的还在路上的请求到了服务器端那边,服务器端又接收、确立,建立连接,显然第二次连接是重复的,这是不必要的资源浪费

如果是三次握手,那么当服务器端接收到第二次重复请求时,发送确认报文给客户端,但客户端并没有发送确认报文,服务器端就会认为客户端并没有这个请求,也就是识别到这是个无效请求,之间也就不会建立连接

传输过程中的seq和ack代表什么?

  • seq是数据包本身的序列号;ack是期望对方继续发送的那个数据包的序列号。

TCP连接四次挥手的过程

首先应该明确客户端进程主动关闭连接,而服务器端进程被动关闭连接

第一次:客户端进程发送连接释放报文 FIN=1,并发送初始序列号seq=u,此时客户端进程进入FIN-WAIT-1状态,客户端进程不再发送数据

第二次:服务器端进程接收到释放报文后,返回一个确认报文ACK=1 ack=u+1 seq=v 此时服务器端进程进入CLOSE-WAIT状态,同时通知高层的应用进程,此时服务器端进程仍可以发送数据,

客户端进程接收到服务器端进程的确认报文后,进入FIN-WAIT-2,等待服务器端进程发送连接释放报文

第三次:等到服务器端进程数据发送完毕后,发送连接释放报文,FIN=1 ACK=1 ack=u+1 seq=w,进入LAST-ACK最后确认状态,等待客户端确认

第四次:客户端进程接收到释放报文后,返回ACK=1 ack=w+1 seq=u+1,进入TIME-WAIT时间等待状态,等待的时间就是2MSL,然后才撤销TCB,进入CLOSED状态,结束TCP连接

服务器端进程接收到确认报文后,就进入CLOSED状态,撤销TCB,结束TCP连接

为什么握手是三次,挥手是四次?

握手时,服务器端进程接收到连接请求后,将确认报文和连接报文都在第二次握手一起发过去;挥手时,服务器端进程接收到释放请求后,先是发送了确认报文,然后再发送释放报文,分两次发送。这就是挥手比握手多一次的原因。

那为什么挥手时要分开发送呢?

要解答这个问题,就要弄懂服务器进程在分开发送的这个过程中,做了些什么?

这段时间属于半关闭状态,服务器端进程通知高层的应用进程、还将一些未发送的数据发送给客户端进程。相当于它还有一些事情没完成,需要给它一点时间,但是又需要给客户端先发送确认,免得客户端以为请求失效了

下面这段引用,顺便讲解了发送ack的目的,主要为了检查对方发送的是否和自己发送的一致

第一次握手:主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,主机B由SYN=1知道,A要求建立联机;

第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1,随机产生seq=7654321的包;

第三次握手:主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功。

完成三次握手,主机A与主机B开始传送数据。