应用程序(浏览器)调用 Socket 库的 connect :
connect(<描述符 >, <服务器 IP 地址和端口号 >, … )
浏览器提供了服务器的 IP 地址和端口号(这能唯一标识一个进程,这模式叫Socket),这些信息会传递给 协议栈 ( *** 作系统的网络控制软件叫作协议栈)中的 TCP 模块。
然后就开始 三次握手 :TCP为了提供可靠的传送,客户端和服务端先发送无内容只有头部的包,来确认能力没问题, 这样就证明连接是通的, 可以正式发数据了. 并且核对了Seq值
主要是为了防止 服务器开销的浪费
2次握手以后, 两个应用程序之间建立了一个全双工 (full-duplex) 的通信。
这个全双工的通信将占用两个计算机之间的通信线路,直到它被一方或双方关闭为止。
如果没有第三次,就是请求方的返回, 不确认 请求方真的可以收到数据 (可能延时导致客户端放弃收这次响应了),
不知道对客户端来说连接已经创建失败了,服务端就一直傻等客户端的永远不会发生(客户端认为已经失败,重新开始握手)的正式发生请求,太浪费了, 会被攻击
包含很多字段,重点是发送方和接收方的端口号,和控制位
客户端(发送方)的套接字准确找到了服务器(接收方)的套接字,也就是搞清楚了我应该连接哪个套接字。
将 头部中的控制位的 SYN 比特(TCP头控制位的其中一位)设置为 1 ,表示连接开始.
TCP 头部创建好之后,接下来 TCP 模块会将信息传递给 IP 模块并委托它进行发送。IP 模块执行网络包发送 *** 作后,网络包就会通过网络到达服务器,然后服务器上的 IP 模块会将接收到的数据传递给 TCP 模块,
服务器的 TCP 模块根据 TCP 头部中的信息找到端口号对应的套接字,也就是说,从处于等待连接状态的套接字中找到与 TCP 头部中记录的端口号相同的套接字就可以了。当找到对应的套接字之后,套接字中会写入相应的信息,并将状态改为正在连接.
上述 *** 作完成后,服务器的 TCP 模块会返回响应,这个过程和客户端一样,在 TCP 头部中设置发送方和接收方端口号以及
SYN 比特,设置为1,表示Seq已设置,
ACK 比特((TCP头控制位的其中另一一位)设为1 ,表示ACK确认号(告知对方收到数据的第几个字节的,这次是发生方的Seq+1)有效,已经收到对方之前发的数据了,
将 TCP头部传递给 IP 模块,并委托 IP 模块向客户端返回响应。
然后,网络包就会返回到客户端,通过 IP 模块到达 TCP 模块,
通过 TCP 头部的信息确认连接服务器的 *** 作是否成功。如果 SYN 为 1 则表示连接成功,这时会向套接字中写入服务器的 IP 地址、端口号等信息,同时还会将状态改为连接完毕。
最后一个步骤,客户端也需要 将 ACK 比特设置为 1 ,表示ACK号生效(值为服务端发来的Seq+q),并发回服务器,告诉服务器刚才的响应包已经收到。
当这个服务器收到这个返回包之后,连接 *** 作才算全部完成。现在,套接字就已经进入随时可以收发数据的状态了,大家可以认为这时有一根管子把两个套接字连接了起来。当然,实际上并不存在这么一根管子,不过这样想比较容易理解,网络业界也习惯这样来描述。这根管子,我们称之为 连接 。只要数据传输过程在持续,也就是在调用 close 断
开之前,连接一直存在。
建立连接之后,协议栈的连接 *** 作就结束了,也就是说 connect 已经
执行完毕,控制流程被交回到应用程序。
SYN flood洪水攻击 防范 待看
保活机制:
https://blog.csdn.net/q1007729991/article/details/70196793
三次握手后会在 各自内存空间 中形成一个 队列空间 ,并建立 socket 。
四次挥手目的是为了安全的销毁双方的连接释放内存,之前开辟的队列空间是为了对方服务的。
第一次握手:建立连接时,客户端发送syn包(syn=x)到服务器,并进入 SYN_SENT 状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入 SYN_RECV 状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入 ESTABLISHED (TCP连接成功)状态,完成三次握手。
答:因为当 Server 端收到 Client 端的 SYN 连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
【问题2】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。
答:3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
现在把三次握手改成仅需要两次握手,死锁是可能发生的 。作为例子,考虑计算机 S 和 C 之间的通信,假定 C 给 S 发送一个连接请求分组,S 收到了这个分组,并发送了确认应答分组。按照两次握手的协定,S 认为连接已经成功地建立了,可以开始发送数据分组。可是,C 在 S 的应答分组在传输中被丢失的情况下,将不知道 S 是否已准备好,不知道 S 建立什么样的序列号,C 甚至怀疑 S 是否收到自己的连接请求分组。在这种情况下,C认为连接还未建立成功,将忽略 S 发来的任何数据分组,只等待连接确认应答分组。而 S 在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。
【问题4】如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP 还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为 2 小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔 75 秒钟发送一次。若一连发送 10 个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)