三次握手:
1、Client端将标志位SYN置为1,随机产生一个值seq=x,Client进入SYN_SEND状态。
2、Server端收到数据包之后,讲SYN和ACK都置为1,ack=x+1,随机产生一个值seq=y,服务端进入SYN_RCVD状态。
3、Client端收到数据包,检查ack是否x+1,ACK是否为1,将标志位ACK置为1,ack=y+1,发送到服务端,此时Client和Server端进入到ESTABLISHED
四次握手:
1、客户端将FIN标志位置为1,ack为x,ack为y,客户端进入FIN_WAIT_1状态
2、服务器端接收到数据,回复给客户端消息,seq=y ack=x+1,服务端进入CLOSE_WAIT状态,客户端接收到服务端数据,进入到FIN_WAIT_2状态
3、服务端发送标志位FIN=1,seq=y+1,ack=x+1报文给客户端,服务端进入LASK_ACK状态
4、客户端收到服务端数据,客户端回复ACK=1, ack=y+1报文,此时客户端状态为TIME_WAIT状态。服务端收到客户端数据,服务端关闭资源。客户端等待2MSL(Max Segment Lift)时间,关闭客户端。
Socket缓冲区工作原理:
在内核空间里,每个socket都有自己的send buffer和receive buffer,可以把这两个buffer理解为队列。
当网卡收到数据之后,经过操作系统一系列处理,把数据写到receive buffer的尾部,写不下就扔了。如果是tcp协议还有会利用滑动窗口控制流量,滑动窗口会告诉对方自己的buffer还有多大,如果receive buffer满了,滑动窗口就会变为0,对方也就不会发数据了。
应用层发起调用receive或read,数据从recievebuffer拷贝到用户控件,即从内核态拷贝到用户态,也就是拷贝到应用程序的内存里,之后操作系统会把receive buffer中已经被读取的数据删除。
为什么三次握手:
为了实现可靠的数据传输,三次握手是为了双方都知道对方的seq序列号。
如果是2次握手,Clent端状态为SYN_SEND,如果第二次握手,Server端进入ESTABLISHED状态,由于网络问题Client端没收到,那么Clent端将一直是SYN_SEND状态
如果二次握手,不是为了防止浪费资源,而是无法确保连接成功
第二次握手,Client端知道了Server端知道了自己的序列号。
第三次握手,Server端知道了Client端知道了自己的序列号。
Server端发送二次握手消息,Server端如果一直收不到Client的三次握手消息,那么Server端在一段时间内会重新进行二次握手。
为什么四次挥手:
客户端发送FIN请求到服务器,表示客户端已经没有数据发送了,此时服务器端回复给客户端ACK,表示服务器端接口到了FIN命令。
服务器端接收到FIN命令,服务器端可能还有数据没发送完,或者服务器端程序数据还没处理完,需要等待处理结束之后服务端给客户端发送FIN命令
为什么四次挥手需要等2MSL(Maximum Segment Life)
如果四次挥手报文丢失,就会重新发送三次挥手命令。
服务端发送三次挥手指令,在1MSL时间内,客户端收到命令。客户端发送ACK,理论上在1MSL(A)时间内,服务器端会收到,如果没收到,服务器端会重新发送三次挥手,客户端需要1MSL(B)时间内收到数据,此时距客户端四次挥手的ACK命令时间为(A+B=2MSL)
如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP设有一个保活计时器,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。