TCP三次挥手四次握手(面试总结)

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

全双工通信。
这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。

2、 为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?

<2020_05>补充

  1. 保证tcp可靠终止连接
  2. 保证迟来的或重发的tcp报文有足够的时间被识别或者丢弃
    这是因为:虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);
    但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文,并保证于此。
    <2020_05>原因2:在linux系统一个tcp端口不能被打开两次以上,如果当前端口处于time_wait状态,那么新链接无法建立,而如果不存在time_wait,新的链接可能会接收到原来链接重发或者迟到的数据(比如上一个链接最后的ack没有被server接收到,那么新的链接建立,反而接收到了,server要发给上一个client的报文)

<2020_05>如果出现了time_wait怎么处理

在实际工作中没有出现这样的问题,因为事先已经将机器优化过了,而不是除了time_wait的问题之后才进行优化。
net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。

经典的两张图

这里写图片描述

这里写图片描述

建立连接协议(三次握手)

  • 客户端发送一个带SYN标志的TCP报文到服务器。这是三次握手过程中的报文1。

  • 服务器端回应客户端的,这是三次握手中的第2个报文,这个报文同时带ACK标志和SYN标志。因此它表示对刚才客户端SYN报文的回应;同时又标志SYN给客户端,询问客户端是否准备好进行数据通讯。

  • 客户必须再次回应服务段一个ACK报文,这是报文段3。

连接终止协议(四次握手)

由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

各种状态详解

CLOSED:

这个没什么好说的了,表示初始状态。

LISTEN:

这个也是非常容易理解的一个状态,表示服务器端的某个SOCKET处于监听状态,可以接受连接了。

SYN_RCVD:

这个状态表示接受到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本上用netstat你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP握手过程中最后一个ACK报文不予发送。因此这种状态时,当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。

SYN_SENT:

这个状态与SYN_RCVD遥相呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,因此也随即它会进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。

ESTABLISHED:

这个容易理解了,表示连接已经建立了。

FIN_WAIT_1:

这个状态要好好解释一下,其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。

而这两种状态的区别是:

FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。

FIN_WAIT_2:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。

TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。

如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。

注:MSL(最大分段生存期)指明TCP报文在Internet上最长生存时间,每个具体的TCP实现都必须选择一个确定的MSL值.RFC 1122建议是2分钟,但BSD传统实现采用了30秒.TIME_WAIT 状态最大保持时间是2 * MSL,也就是1-4分钟.

CLOSING:

这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报文的情况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET连接。

CLOSE_WAIT:

这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。

LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。

最后有2个问题的回答,我自己分析后的结论(不一定保证100%正确)

对原作者文章,进行了重新排版,和部分错别字校正。
但未联系到原作者,如有侵权可联系我删除文章
http://blog.sina.com.cn/s/blog_8e5d24890102w9yi.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/382644.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

csdn怎么快速转载别人的文章

如何转载 用谷歌浏览器加载文章地址&#xff0c;打开文章F12打开Developer Tools&#xff0c;并打开Elements页面 将文章开头部分的文字作为关键字在Elements界面搜索 以此文为例&#xff1a;http://blog.csdn.net/aggressive_snail/article/details/54375876 搜索找了好久关…

解释性语言和汇编性语言对比

解释性语言和编译型语言的区别和不同解释性语言编译型语言概念计算机不能直接的理解高级语言&#xff0c;只能直接理解机器语言&#xff0c;所以必须要把高级语言翻译成机器语言&#xff0c;计算机才能执行高级语言的编写的程序。翻译的方式有两种&#xff0c;一个是编译&#…

C++ 菱形继承 的 对象模型01

先看 普通菱形继承 #include <iostream> #include <string> using namespace std; class Animal {int a_age; }; class Sheep : public Animal {}; class Tuo : public Animal {}; class SheepTuo : public Sheep, public Tuo {}; void test1() {cout << …

伙伴算法

通常情况下&#xff0c;一个高级操作系统必须要给进程提供基本的、能够在任意时刻申请和释放任意大小内存的功能&#xff0c;就像malloc 函数那样&#xff0c;然而&#xff0c;实现malloc 函数并不简单&#xff0c;由于进程申请内存的大小是任意的&#xff0c;如果操作系统对ma…

CRC冗余校验举例和原理

什么是CRC校验&#xff1f;CRC即循环冗余校验码&#xff1a;是数据通信领域中最常用的一种查错校验码&#xff0c;其特征是信息字段和校验字段的长度可以任意选定。循环冗余检查&#xff08;CRC&#xff09;是一种数据传输检错功能&#xff0c;对数据进行多项式计算&#xff0c…

C++ 多态原理初步01

当父类 Animal 的speak 前面加上 virtual 关键字之后&#xff0c;这个speak函数就变成了虚函数&#xff0c;Animal类结构发生了变化&#xff0c; 有了一个vfptr &#xff08;虚函数指针&#xff09;&#xff0c;指向了vftable&#xff08;虚函数表&#xff09;, 这个虚函数表里…

面向对象与面向过程的本质的区别

https://blog.csdn.net/jerry11112/article/details/79027834 如果你很想搞明白面向对象是什么&#xff0c;面向过程是什么&#xff0c;或者说二者之间的区别是什么&#xff0c;那么就花费一点时间来研读一下这篇博客&#xff0c;你一定会有很大的收获的&#xff01; 一、面向…

grep参数说明及常用用法

grep参数说明及常用用法 查看文件内容 [koulocalhost ~]$ more size.txt b124230 b034325 a081016 m7187998 m7282064 a022021 a061048 m9324822 b103303 a013386 b044525 m8987131 B081016 M45678 B103303 BADc2345 [] : 查看符合范围内的信息 [koulocalho…

进程的状态与种类

● 运行&#xff1a;正占用处理器   ● 就绪&#xff1a;只要获得处理器即可运行。   ● 阻塞&#xff1a;正等待某个事件&#xff08;如I/O完成&#xff09;的发生。  在不少系统中&#xff0c;还增加了两种基本状态&#xff1a;   ● 新状态&#xff1a;一个进程刚刚…

int * p =NULL;和*p =NULL的区别a和a的区别

1.int * p NULL;和*p NULL的区别 1 .int * p NULL int *pNULL&#xff1b;定义一个指针变量p&#xff0c;其指向的内存里面保存的是int类型的数据&#xff1b;再定义变量p的同时把p的值设置为0x00000000&#xff0c; 而不是把*p的值设置为0x00000000 2.*p NULL int i 10&am…

当我们说TCP是可靠协议时,我们真正表达的是什么

转载出处&#xff1a;https://blog.csdn.net/dog250/article/details/82177299 很明确地说&#xff0c;从通信意义上推敲&#xff0c;TCP一点都不可靠。一个抽象的协议&#xff0c;怎么可能左右介质来保证可靠&#xff0c;不存在的。但凡是经由某种介质的通信行为均不可能是绝对…

有一个小白程序员,写了一个只能对5个数字进行排序的函数,现在有25个不重复的数字,

题目&#xff1a;有一个小白程序员&#xff0c;写了一个只能对5个数字进行排序的函数&#xff0c;现在有25个不重复的数字&#xff0c;请问小白同学最少调用几次该函数&#xff0c;可以找出其中最大的三个数&#xff1f; A.5 B.6 C.7 D.8 答案&#xff1a;C 解析&#xf…

初始序列为1 8 6 2 5 4 7 3一组数采用堆排序,当建堆(小根堆)完毕时,堆所对应的二叉树中序遍历序列为

初始序列为1 8 6 2 5 4 7 3一组数采用堆排序&#xff0c;当建堆&#xff08;小根堆&#xff09;完毕时&#xff0c;堆所对应的二叉树中序遍历序列为&#xff1a;&#xff08;&#xff09; 8 3 2 5 1 6 4 7 3 2 8 5 1 4 6 7 3 8 2 5 1 6 7 4 8 2 3 5 1 4 7 6 A

设一组初始记录关键字序列为(25,50,15,35,80,85,20,40,36,70)进行一趟归并后的结果为

设一组初始记录关键字序列为(25&#xff0c;50&#xff0c;15&#xff0c;35&#xff0c;80&#xff0c;85&#xff0c;20&#xff0c;40&#xff0c;36&#xff0c;70)&#xff0c;其中含有5个长度为2的有序子表&#xff0c;则用归并排序的方法对该记录关键字序列进行一趟归并…

文字常量区和栈区考点

求以下程序输出结果 #include <stdio.h>char * fun1() {char * str "hello";return str; }char * fun2() {char str[] "world";return str; } int main() {printf("%s\n", fun1()); printf("%s\n", fun2()); return 0; }结…

判断栈的压入和弹出

序列1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5是压栈序列。序列 4&#xff0c;3&#xff0c;5&#xff0c;1&#xff0c;2是弹出序列。判断第二个是不是弹出序列 三步走 如果下一个弹出的数字刚好是栈顶数字&#xff0c;直接弹出如果不在栈顶&#xff0c;就一直…

动态规划学习笔记2

题目描述&#xff1a; 在一个mn的棋盘的每一格都放有一个礼物&#xff0c;每个礼物都有一定的价值&#xff08;价值大于0&#xff09;。你可以从棋盘的左上角开始拿格子里的礼物&#xff0c;并每次向右或者向下移动一格直到到达棋盘的右下角。给定一个棋盘及其上面的礼物&…