CRCMS

高山仰止,景行行止,虽不能至,心向往之

大道至简


Http/TCP 基础协议

请求头

1
2
3
4
方法+空格+URI+空格+协议版本\r\n
首部字段\r\n
\r\n
主体

如:

1
2
3
4
5
post /api/v1/register http/1.1
Host: firmeve.com
Connection: keep-alive
Content-Type: application/json
{"name":"simon","mobile":""}

响应头

1
2
3
4
协议版本+空格+状态码+状态描述\r\n
首部字段\r\n
\r\n
主体

图片展示可能更为清晰:
http协议格式

TCP 连接3次握手,4次挥手

TCP基础协议说明

tcp_message

如图:

  • 源端口,目的端口各占16bit
  • 序号(seq) 32bit
  • 确认号(ack) 32bit ack=seq+1 (发起方req+1)
  • 标志位
    • URG 紧急指针
    • ACK 确认序号有效
    • PSH 接收方应该尽快将这个报文交给应用层
    • RST 重置连接
    • SYN 发起一个连接
    • FIN 释放连接

3次握手

第1次握手

Client发送SYN标识以及Seq序号到Server

Client—-(SYN=1,Seq=N)—->Server

第2次握手

Server收到Client消息后

  • 将ack确认号设置为N+1
  • 并设置seq发送号为Y(代号)
  • 设置SYN以及ACK(确认序号和ack确认号不同) 为1
  • 发送给Client

Server———(SYN=1,Seq=Y,ack=N+1(这里的ack是确认号,不是确认序号))——>Client
Server收到SYN包,返回自己的SYN和ACK包

第3次握手

Client 发送ACK到Server

  • 将server的seq+1(即ack=Y+1)
  • 设置ACK确认序号为1
  • 设置自身的seq=Z

Client ——(Seq=Z,ACK=Y+1)——–> Server

对于上述描述,这是一张更为详细的图

tcp_message
tcp_message

为什么必须是3次握手而不是2次

为了验证4个目标,Client和Server的收发能力

  • 第一次 验证了Client的发送能力
  • 第二次验证了Server的接收能力和发送能力
  • 第三次为了验证Client的接收能力

详细说明

第一次握手:客户端发送网络包,服务端收到了。这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。

第二次握手:服务端发包,客户端收到了。这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。 从客户端的视角来看,我接到了服务端发送过来的响应数据包,说明服务端接收到了我在第一次握手时发送的网络包,并且成功发送了响应数据包,这就说明,服务端的接收、发送能力正常。而另一方面,我收到了服务端的响应数据包,说明我第一次发送的网络包成功到达服务端,这样,我自己的发送和接收能力也是正常的。

第三次握手:客户端发包,服务端收到了。这样服务端就能得出结论:客户端的接收、发送能力,服务端的发送、接收能力是正常的。 第一、二次握手后,服务端并不知道客户端的接收能力以及自己的发送能力是否正常。而在第三次握手时,服务端收到了客户端对第二次握手作的回应。从服务端的角度,我在第二次握手时的响应数据发送出去了,客户端接收到了。所以,我的发送能力是正常的。而客户端的接收能力也是正常的。

经历了上面的三次握手过程,客户端和服务端都确认了自己的接收、发送能力是正常的。之后就可以正常通信了。

每次都是接收到数据包的一方可以得到一些结论,发送的一方其实没有任何头绪。我虽然有发包的动作,但是我怎么知道我有没有发出去,而对方有没有接收到呢?

而从上面的过程可以看到,最少是需要三次握手过程的。两次达不到让双方都得出自己、对方的接收、发送能力都正常的结论。其实每次收到网络包的一方至少是可以得到:对方的发送、我方的接收是正常的。而每一步都是有关联的,下一次的“响应”是由于第一次的“请求”触发,因此每次握手其实是可以得到额外的结论的。比如第三次握手时,服务端收到数据包,表明看服务端只能得到客户端的发送能力、服务端的接收能力是正常的,但是结合第二次,说明服务端在第二次发送的响应包,客户端接收到了,并且作出了响应,从而得到额外的结论:客户端的接收、服务端的发送是正常的。

用表格总结一下:

三次握手验证示例图

衍生SYN攻击

在三次握手过程中,服务器发送SYN-ACK之后,收到客户端的ACK之前的TCP连接称为半连接(half-open connect).此时服务器处于Syn_RECV状态.当收到ACK后,服务器转入ESTABLISHED状态.Syn攻击就是 攻击客户端 在短时间内伪造大量不存在的IP地址,向服务器不断地发送syn包,服务器回复确认包,并等待客户的确认,由于源地址是不存在的,服务器需要不断的重发直 至超时,这些伪造的SYN包将长时间占用未连接队列,正常的SYN请求被丢弃,目标系统运行缓慢,严重者引起网络堵塞甚至系统瘫痪。Syn攻击是一个典型的DDOS攻击。检测SYN攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击.在Linux下可以如下命令检测是否被Syn攻击netstat -n -p TCP | grep SYN_RECV一般较新的TCP/IP协议栈都对这一过程进行修正来防范Syn攻击,修改tcp协议实现。主要方法有SynAttackProtect保护机制、SYN cookies技术、增加最大半连接和缩短超时时间等.但是不能完全防范syn攻击。

四次挥手

4次挥手
tcp_message

  1. 客户端发送一个FIN段,并包含一个希望接收者看到的自己当前的序列号x. 同时还包含一个ACK表示确认对方最近一次发过来的数据。
  2. 服务端将x值加1作为ACK序号值,表明收到了上一个包。这时上层的应用程序会被告知另一端发起了关闭操作,通常这将引起应用程序发起自己的关闭操作。
  3. 服务端发起自己的FIN段,ACK=x+1, Seq=y
  4. 客户端确认。ACK=y+1

为什么建立连接是三次握手,而关闭连接却是四次挥手呢?

这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方是否现在关闭发送数据通道,需要上层应用来决定,因此,己方ACK和FIN一般都会分开发送。

参考链接

TCP的三次握手四次挥手

三次握手,四次挥手”你真的懂吗?

一次完整的HTTP请求过程