TCP包头

  • 序列号:表示本报文段所发送数据的第一个字节的编号。在TCP连接中所传送的字节流的每一个字节都会按顺序编号。由于序列号由32位表示,所以每2^32个字节,就会出现序列号回绕,再次从 0 开始。

  • 确认号:表示接收方期望收到发送方下一个报文段的第一个字节数据的编号。也就是告诉发送方:我希望你(指发送方)下次发送的数据的第一个字节数据的编号为此确认号。

  • 数据偏移:表示TCP报文段的首部长度,共4位,由于TCP首部包含一个长度可变的选项部分,需要指定这个TCP报文段到底有多长。它指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远。该字段的单位是32位(即4个字节为计算单位),4位二进制最大表示15,所以数据偏移也就TCP首部最大60字节。

  • URG:表示本报文段中发送的数据是否包含紧急数据。后面的紧急指针字段(urgent pointer)只有当URG=1时才有效

  • ACK:表示是否前面确认号字段是否有效。只有当ACK=1时,前面的确认号字段才有效。TCP规定,连接建立后,ACK必须为1,带ACK标志的TCP报文段称为确认报文段

  • PSH:提示接收端应用程序应该立即从TCP接收缓冲区中读走数据,为接收后续数据腾出空间。如果为1,则表示对方应当立即把数据提交给上层应用,而不是缓存起来,如果应用程序不将接收到的数据读走,就会一直停留在TCP接收缓冲区中

  • RST:如果收到一个RST=1的报文,说明与主机的连接出现了严重错误(如主机崩溃),必须释放连接,然后再重新建立连接。或者说明上次发送给主机的数据有问题,主机拒绝响应,带RST标志的TCP报文段称为复位报文段

  • SYN:在建立连接时使用,用来同步序号。当SYN=1,ACK=0时,表示这是一个请求建立连接的报文段;当SYN=1,ACK=1时,表示对方同意建立连接。SYN=1,说明这是一个请求建立连接或同意建立连接的报文。只有在前两次握手中SYN才置为1,带SYN标志的TCP报文段称为同步报文段

  • FIN:表示通知对方本端要关闭连接了,标记数据是否发送完毕。如果FIN=1,即告诉对方:“我的数据已经发送完毕,你可以释放连接了”,带FIN标志的TCP报文段称为结束报文段

三次握手

  所谓三次握手(Three-Way Handshake)即建立TCP连接,就是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发,整个流程如下图所示:

  1.第一次握手:客户端向服务器端发送一个请求,SYN为1,随机产生一个seq=x值,并且客户端进入SYN-SENT状态,等待服务器端确认。

  2.第二次握手:服务器端接收到来自客户端的请求,看到SYN值是1,seq是一个随机数,所有它也发一个确认码个客户端,SYN是1,并且ACK是1,ack=x+1,seq=y,然后服务器进入到SYN-RCVD(同步收到)。

  3.第三次握手:客户端收到确认后,检查ack是否为x+1,ACK是否为1,SYN是否为1,如果正常,客户端就把ACK为1 seq=x+1,ack=y+1,发送给服务器端。服务器端都到后检查ack是否为y+1 , ACK是否为1,如果正常则建立连接,客户端和服务器端就都进入ESTAB-LISHED状态,可以开始通信了。

SYN攻击:
在三次握手的过程中,当服务器端发送SYN-ACK后,收到客户端的ACK之前的TCP连接,我们称为半连接,这个时候服务器处于SYN-RCVD状态,只有收到下一个SYN后服务器才会进入到ESTAB-LISHED状态,黑客一般会利用这一点,用软件对服务器建立大量的半连接,服务器短时因为有太多的半连接,没一个半连接它都有去发送请求,而得不到回应,这些伪造的SYN就会占用大量的未连接列队,导致列队过满而被抛弃,这样会导致网络堵塞或瘫痪。典型的就是DDOS攻击。检测SYN攻击的方式非常简单,即当服务器上有大量半连接状态且源IP地址是随机的,则可以断定遭到SYN攻击了,使用如下命令可以让之现行:

#netstat -nap | grep SYN_RECV

四次挥手过程

所谓四次挥手(Four-Way Wavehand)即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发,整个流程如下图所示:

由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,上图描述的即是如此。
  1.第一次挥手:客户端主动提出关闭请求,发送FIN=1 seq=u给服务器端同时客户端进入到FIN-WAIT-1等待状态。
  2.第二次挥手:服务器端收到FIN请求后,就发送一个ACK=1 seq=v ack=u+1 给客户端,然后进入到close-wait状态,同时客户端进入到FIN-WAIT-2状态。
  3.第三次挥手:等待数据传输完成后,服务器端再发一个FIN=1 ACK=1 seq=w ack=u+1 给客户端然后服务器端进入到LAST-ACK最后确认的状态。
  4.第四次挥手:客户端收到FIN后,进入到TIME-WAIT状态,接着发送一个ACK=1 给服务器端,服务器端收到确认后就会进入到closed状态,同时客户端在等待时间后也会进入到closed状态,这样两台机器就断开连接了。

一般的断开连接是四次,但是在实际的环境中比较复杂,可能双方同时发送FIN请求,或者网络突然断开,再或者网络堵塞都会造成4次挥手失败。