应用程序(浏览器)调用 Socket 库的 connect :
connect(< 描述符 >, < 服务器 IP 地址和端口号 >, … )
浏览器提供了服务器的 IP 地址和端口号(这能唯一标识一个进程,这模式叫Socket),这些信息会传递给协议栈(操作系统的网络控制软件叫作协议栈)中的 TCP 模块。
然后就开始 三次握手:TCP为了提供可靠的传送,客户端和服务端先发送无内容只有头部的包,来确认能力没问题, 这样就证明连接是通的, 可以正式发数据了. 并且核对了Seq值
有第三次的原因
主要是为了防止 服务器开销的浪费
2次握手以后, 两个应用程序之间建立了一个全双工 (full-duplex) 的通信。
这个全双工的通信将占用两个计算机之间的通信线路,直到它被一方或双方关闭为止。
如果没有第三次,就是请求方的返回,不确认 请求方真的可以收到数据(可能延时导致客户端放弃收这次响应了),
不知道对客户端来说连接已经创建失败了,服务端就一直傻等客户端的永远不会发生(客户端认为已经失败,重新开始握手)的正式发生请求,太浪费了, 会被攻击
头部
包含很多字段,重点是发送方和接收方的端口号,和控制位
- 序号Seq: 如果上一个数据包头Seq是107,长度100, 本包的Seq就该写207(收到的ACK确认好也是207)
- ACK确认号(ACK控制位为1才有效): 如果收到的数据包 Seq 301 长度200, 回复就该是ACK 501
- 紧急指针: URG 标志位1 才有效
客户端(发送方)的套接字准确找到了服务器(接收方)的套接字,也就是搞清楚了我应该连接哪个套接字。
第一次: 客户端->服务端 [SYN]Seq=0
将头部中的控制位的 SYN 比特(TCP头控制位的其中一位)设置为 1,表示连接开始.
将 SYN 控制位设为1 并发送给服务器的操作,同时设置序号字段的值Seq就代表序号的初始值
说 SYN 为 1 表示进行连接,这是因为将SYN 设为 1 并告知初始序号这一操作仅在连接过程中出现
SYN 是 Synchronize(同步)的缩写,意思是通过告知初始序号使通信双方保持步调一致,以便完成后续的数据收发检查,这才是 SYN 原本的含义。
TCP 头部创建好之后,接下来 TCP 模块会将信息传递给 IP 模块并委托它进行发送。IP 模块执行网络包发送操作后,网络包就会通过网络到达服务器,然后服务器上的 IP 模块会将接收到的数据传递给 TCP 模块,
服务器的 TCP 模块根据 TCP 头部中的信息找到端口号对应的套接字,也就是说,从处于等待连接状态的套接字中找到与 TCP 头部中记录的端口号相同的套接字就可以了。当找到对应的套接字之后,套接字中会写入相应的信息,并将状态改为正在连接.
第二次: 服务端->客户端 [SYN,ACK] Seq=0 Ack=1
上述操作完成后,服务器的 TCP 模块会返回响应,这个过程和客户端一样,在 TCP 头部中设置发送方和接收方端口号以及
SYN 比特,设置为1,表示Seq已设置,
ACK 比特((TCP头控制位的其中另一一位)设为1,表示ACK确认号(告知对方收到数据的第几个字节的,这次是发生方的Seq+1)有效,已经收到对方之前发的数据了,
将 TCP头部传递给 IP 模块,并委托 IP 模块向客户端返回响应。
第三次: 客户端->服务端 [ACK] Seq=1 Ack=1
然后,网络包就会返回到客户端,通过 IP 模块到达 TCP 模块,
通过 TCP 头部的信息确认连接服务器的操作是否成功。如果 SYN 为 1 则表示连接成功,这时会向套接字中写入服务器的 IP 地址、端口号等信息,同时还会将状态改为连接完毕。
最后一个步骤,客户端也需要将 ACK 比特设置为 1,表示ACK号生效(值为服务端发来的Seq+q),并发回服务器,告诉服务器刚才的响应包已经收到。
当这个服务器收到这个返回包之后,连接操作才算全部完成。现在,套接字就已经进入随时可以收发数据的状态了,大家可以认为这时有一根管子把两个套接字连接了起来。当然,实际上并不存在这么一根管子,不过这样想比较容易理解,网络业界也习惯这样来描述。这根管子,我们称之为连接。只要数据传输过程在持续,也就是在调用 close 断
开之前,连接一直存在。
建立连接之后,协议栈的连接操作就结束了,也就是说 connect 已经
执行完毕,控制流程被交回到应用程序。
其他
SYN flood洪水攻击 防范 待看
保活机制:
https://blog.csdn.net/q1007729991/article/details/70196793