前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >面试官直呼TCP三次握手和四次挥手问题答得完美

面试官直呼TCP三次握手和四次挥手问题答得完美

原创
作者头像
龙跃十二
修改于 2020-04-14 02:37:42
修改于 2020-04-14 02:37:42
1.8K20
代码可运行
举报
运行总次数:0
代码可运行

少点代码,多点头发

三次握手建立链接,四次挥手断开链接。这个问题算非常经典的问题,也是面试官非常喜欢问的问题。

不夸张的说,龙叔在校招面试的时候每一家公司都问到过关于三次握手和四次挥手相关的问题,相信大家也都差不多被面试官各种怼。

这个问题的重要性,已经意识到。不说废话了,接下来就是听龙叔给你安排的明明白白。

先画个图,看下TCP的建立连接 和 断开连接的整体过程。

tcp三次握手四次挥手

看完这个图相信聪明的你在整体对三次握手和四次挥手有了一些基本把控。但是,里面的细节肯定是会有些生疏或者模糊的,接下来就一个一个问题的揭露本质。

在解释之前先看点基础知识做做铺垫。

TCP状态转移解释

状态

描述

CLOSED

阻塞或关闭状态,表示主机当前没有正在传输或者建立的链接

LISTEN

监听状态,表示服务器做好准备,等待建立传输链接

SYN RECV

收到第一次的传输请求,还未进行确认

SYN SENT

发送完第一个SYN报文,等待收到确认

ESTABLISHED

链接正常建立之后进入数据传输阶段

FIN WAIT1

主动发送第一个FIN报文之后进入该状态

FIN WAIT2

已经收到第一个FIN的确认信号,等待对方发送关闭请求

TIMED WAIT

完成双向链接关闭,等待分组消失

CLOSING

双方同时关闭请求,等待对方确认时

CLOSE WAIT

收到对方的关闭请求并进行确认进入该状态

LAST ACK

等待最后一次确认关闭的报文

再看下TCP的报文格式

TCP报文格式

首部有20字节的固定长度,含义如下:

  1. 源端口和目的端口

各占2字节,就是存储源端口号和目的端口的

  1. 序号seq

占4字节,表示的范围就是整形的范围[0~2^32]。序号使用在给数据部分每个字节进行编号的,编号方式是mod 2^32 。

  1. 确认号ack

占4字节,范围也是无符号整数的范围。使用在对端传输给我的数据最后一个字节序号,例如A传输给B 101—500,此时B返回的确认号一定是小于等于501的。当B段正确接收数据之后才会返回确认号,换句话说确认号之前的数据已经全部接收。

  1. 数据偏移

占4bit,数据偏移很多人很容易想到是不是表示数据的长度,那就错了。偏移嘛,指的是TCP起始位置到数据部分的起始位置的偏移,也就是TCP首部的长度。

  1. 保留

占6bit,保留字段顾名思义,就是为今后使用,默认置为0。

  1. 紧急URG控制位

占用1bit,URG=1,表示紧急指针有效,此时tcp数据优先传输。相当于生活中的紧急通道,特殊情况时使用。 在网络中也会有特殊情况,例如,发送一个很长的程序在远程服务器上运行,此时发现程序有bug,需要中断运行,因此我们从键盘输入Ctrl c,假如不使用紧急数据,需要在缓冲区里排队,都知道是bug了,还要排队,这怕是要出锅啊。 此时使用紧急数据传输,不需要排队,直接中断程序是不是更符合我们的预期。 需要注意一点是,即使窗口为0时,也可以发送紧急数据。

如何使用紧急URG控制位,在socket编程中send函数flag参数

send(int socket, const void *buffer, size_t length, int flags);

flags参数传MSG_OOB宏时,表示此时有紧急数据。MSG_OOB是个宏,

  1. 确认ACK

占1bit,当ACK=1时生效。TCP有条硬性规定,当建立链接成功后所有传输的数据报文都必须把ACK置为1。

  1. 推送PSH

占1bit,发送方把PSH置为1时 会立即发送该数据包,接收方收到PSH=1的报文会立即处理交付给应用层处理。是不是感觉和URG很像,其实还是有些区别的。

  • 两者相同点:

URG与PSH两者都使用于紧急处理的情况,用来快速传输紧急数据。

  • 两者不同点

URG置为1时,对于发送发,“带外数据”与正常情况下应该发送的消息数据一起,封装成数据报发送,省去了在队列中等待的时间。 在接收方,解析报文后,获取数据之后还是要放在缓存区中,等待满了之后在向上往应用层交付。

PSH置为1时,对于发送方,表明这些数据不需要等向下发送的缓存区满,立刻封装成报文,发送,省去了等待发送缓存区到达满的状态的时间。 在接收方,也不需要等接受缓存区满,直接向上交付给应用层。

  1. 复位RST

占1bit,当RST=1时,TCP会主动释放链接,两种情况会用上。 TCP出现严重差错时,会主动释放连接,重建链接,传输数据。 遇到非法报文或者拒绝连接时会把RST置为1.

  1. 同步SYN

占1bit,同步控制位,用来在传输连接建立时同步传输连接序号。 SYN=1时,表示这是一个连接请求或连接确认报文。 SYN=1,ACK=0,表明这是一个连接请求数据段,如果对方同意建立连接,则对方会返回一个SYN=1、ACK=1的确认。

  1. FIN控制位

占1bit,用于释放一个传输连接。 FIN=1时,表示数据已全部传输完成,发送端没有数据要传输了,要求释放当前连接,但是接收端仍然可以继续接收还没有接收完的数据。 FIN=0,正常传输数据。

  1. 窗口大小

占16bit,2byte,用于表示发送方可以接受的最大数据大小。 该窗口是动态变化的,用作流量控制时使用。

  1. 检验和

占16bit,2byte,用于对TCP头部,伪头部,数据三个部分进行校验。

  1. 紧急指针

占16bit,2byte,用于记录紧急数据的末尾在数据段中的位置。 当URG=1时,该指针才生效。

  1. 可选项

可选项最长可达40byte,是可选的,可以没有。当可选项不存在时,TCP头部长度为20byte。 可选项可以包括窗口缩放选项(Window ScaleOption,WSopt)、MSS(最大数据段大小)选项、SACK(选择性确认)选项、时间戳(Timestamp)选项等。

  1. 数据

TCP数据部分,由应用层应用程序提交的数据。

TCP头部是基础知识,必须了解才能更好的理解TCP数据如何封装和传输,以及在建立链接和断开链接时都在操作那些地方。

三次握手建立连接

三次握手如何建立连接?

三次握手建立链接

从图中可以清楚的看到,三次握手的过程,我在在把过程清楚的解释一遍,顺便说下每个过程容易被问到的知识点。

采用C/S模式解释,假设C端发起传输请求。

在发送建立链接请求之前,C端是保持CLOSED状态,S端最开始也是处于CLOSED状态,当执行listen函数套接字进入被动监听状态

所谓被动监听,是指当没有客户端请求时,套接字处于“睡眠”状态,只有当接收到客户端请求时,套接字才会被“唤醒”来响应请求。

第一次:C端发送SYN=1的请求报文,此时C端进入SYN SENT状态,等待服务器确认。

此时如果报文丢失发送不到对端会如何?

C端发送报文之后会启动一个定时器,在超时之后未收到S端的确认,会再次发送SYN请求,每次尝试的时间会是第一次的二倍,如果总的总尝试时间为75秒,此次建立链接失败。

第二次:S端收到C端发送的SYN报文(建立链接请求)后,S端必须返回确认号并且同时发送一条SYN报文,此时进入SYN RCVD状态。

为啥要连带发送SYN报文?

TCP是全双工通信,协议规定当收到建立链接请求后必须返回序列号,同时建立本端到对端的通信链接。这也叫做捎带应答机制。

如果第二次报文丢失怎么办?

在发送完ACK+SYN报文后会启动一个定时器,超时没有收到ACK确认,会再次发送,会进行多次重试。超时时间依旧每次翻倍,重试次数可设置。 修改 /proc/sys/net/ipv4/tcp_synack_retries 的值

第三次:C端收到S端发的ACK+SYN报文,需要返回一个应答ACK的报文,此时该连接会进入半连接状态的队列,当S端收到ACK后,一条完整的全双工TCP链接建立完成,双方进入ESTABLISHED状态。

这里有个常用攻击手段,攻击者伪造一个SYN请求发送给服务端,服务端响应之后,会收不到C端的ACK确认,服务端会不断的重试,默认会重试五次。 此时服务端会维持这个链接的所有资源,如果有大量这样的请求,服务端的资源会被耗完。 这就是DOS攻击。

如果第三次报文丢失怎么办?

S端在发出ACK+SYN报文后会启动一个定时器,在超时触发还没收到ACK就确认是丢失了,会重试一次发送。

这里面的每个状态都必须搞明白,面试官也超级爱问上面的状态转移。

龙叔还遇到过一个面试官问我用过socket编程么?问我用过哪些socket函数?

C端socket编程代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//C端
#define PORT  8080
#define BUFFER_SIZE 1024
int main(int argc, char **argv)
{
    //定义IPV4的TCP连接的套接字描述符
    int sock_cli = socket(AF_INET,SOCK_STREAM, 0);
    //定义sockaddr_in
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr(argv[1]);
    servaddr.sin_port = htons(PORT);  
 
    //连接服务器,成功返回0,错误返回-1
    int ret = connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr));
 
    //客户端将控制台输入的信息发送给服务器端,服务器原样返回信息,阻塞
    while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
    {   
        ret=send(sock_cli, sendbuf, strlen(sendbuf),0); ///发送
        recv(sock_cli, recvbuf, sizeof(recvbuf),0); ///接收
        fputs(recvbuf, stdout);
    }
 
    close(sock_cli); // 关闭连接
    return 0;
}

S端socket编程代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main(int argc, char **argv)
{
    //定义IPV4的TCP连接的套接字描述符
    int server_sockfd = socket(AF_INET,SOCK_STREAM, 0);
    //定义sockaddr_in
    struct sockaddr_in server_sockaddr;
    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_sockaddr.sin_port = htons(PORT);
 
    //bind成功返回0,出错返回-1
    if(bind(server_sockfd,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))==-1)
 
    //listen成功返回0,出错返回-1,允许同时监听的连接数为QUEUE_SIZE
    if(listen(server_sockfd,QUEUE_SIZE) == -1)
 
    for(;;)
    {
        struct sockaddr_in client_addr;
        socklen_t length = sizeof(client_addr);
        //进程阻塞在accept上,成功返回非负描述字,出错返回-1
        int conn = accept(server_sockfd, (struct sockaddr*)&client_addr,&length);
 
        //处理数据部分
      ...
    }
 
    close(server_sockfd);
    return 0;
}
为什么需要三次握手建立链接,2次可以么,4次行不行?

这问题问的,面试官是咋了?在这明知故问的,整些有的没的。肯定是不行啊,RFC 标准就是这样写的啊。

可不敢这样回答啊,标准是说的三次握手建立链接,可没说四次不行啊。要是这样答,妥妥的会收到,同学我们今天的面试到此基本结束了,你回家等消息...

龙叔来说说这个问题,为什么不能两次?

如果第二次不发送SYN+ACK,只是发送确认应答消息ACK,会造成只能建立单向通信,而且不能应答。而TCP是全双工通信的,而且必须保证可靠性。

如果第二发送SYN+ACK,不用应答。此时会出现三种情况

一、二次握手失败,C端会重复发送SYN报文,等待对端发送确认报文,S端会保存tcp连接的所有资源,大量的这种情况会导致S资源耗尽。

二、二次握手成功,S收不到ACK会重复发送SYN+ACK报文。

三、二次握手完以后,双方以为连接建立成功,即可开始通信。假如此时连接并没有真的建立成功,S端开始发送消息,会造成网络拥堵发生。

为什么不能是四次?

四次其实原则上来说是可以的,就是把第二次的ACK和SYN分两次发送。在理论上是完全可以行得通的,但是TCP本着节约网络网络资源的前提。

还有一种是不拆开二次握手的捎带应答,三次握手之后C端继续发送SYN报文,其时这是徒劳的。第三次完成以后链接已经建立,后面无论多少次都是徒劳。

如果双方同时建立连接,会发生什么情况?

TCP同时建立链接

这就是双方同时建立链接的情况,情况还不错,反正能建立成功,这点是肯定的。但是要注意两点

第一、此时只会建立一条全双工的TCP链接,不是两条。

第二、双方没有CS之分,两端都是同时承担两个角色,客户端和服务器。

四次挥手断开链接

先整个图看下四次挥手的整个过程和状态转移。状态转移会考看仔细点。

四次挥手断开链接

依旧采用C/S模式解释此过程。

第一次:当C端的应用程序结束数据传输是,会向S端发送一个带有FIN附加标记的报文段(FIN表示英文finish),此时C端进入FIN_WAIT1状态,C端不能在发送数据到S端。

第二次:S端收到FIN报文会响应一个ACK报文,S端进入CLOSE_WAIT状态。进入此状态后S端把剩余未发送的数据发送到C端,C端收到S端的ACK之后,进入FIN_WAIT2状态。

同时继续接受S端传输的其他数据包。

第三次:S端处理完自己待发送的数据之后,也会发送FIN断开链接的请求,S端进入LAST_ACK状态。

第四次:C端收到S端的断开链接请求后会启动一个定时器,该定时器时长是2MSL(最大段报文生存时间),同时发送最后一次ACK报文。

为什么要四次挥手?

TCP是全双工的通信机制,每个方向必须单独进行关闭。 TCP传输连接关闭的原则如下: 当一端完成它的数据发送任务后就可以发送一个FIN字段置1的数据段来终止这个方向的数据发送;当另一端收到这个FIN数据段后,必须通知它的应用层 对端已经终止了那个方向的数据传送。

为什么不能用三次握手中捎带应答机制减少一次握手?

这点到是很迷惑人,但是掌握了TCP传输的一些细节就会发现并不难。 TCP是全双工通信的,S收到断开链接请求后只是表示C端不会传输数据到S端了,但是并不表示S端不传输数据到C端。 如果采用捎带应答,S端将无法把剩余的数据传输到C端。

为何最后一次ACK之后需要等待2MSL的时间?

网络是不可靠的,TCP是可靠协议,必须保证最后一次报文送达之后才能断开链接,否则会再次收到S端的FIN报文信息。 而等待2MSL时间就是为了保证最后最后一次报文丢失时还能重新发送。

为何是2MSL的时间?

2MSL是报文一个往返的最长时间,假设小于这个时间会发生,ACK丢了,但是还没接收到对方重传的FIN我方就重新发送了ACK。

如果已经建立了连接,但是客户端突然出现故障了怎么办?

这个不难TCP自己做了保证,TCP默认有个定时器,每次收到客户端的请求后会把定时器设置好,通常设置两小时,超过两小时还没收到数据。 服务端会发送一个探测报文,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

总结

三次握手和四次挥手的知识基本告一段落了,就讲到这里了,如果有什么不明白的地方可以加我微信探讨。

后面还会出一篇网络编程常用的linux命令行工具,比如ping、tcpdump、netstat、nc等等,在出一篇计算机网络的总结文章。计算机网络这部分基本完结了,如果又不懂得可以看看公号里面前面的文章。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
2 条评论
热度
最新
写的太好了
写的太好了
11点赞举报
谢谢支持
谢谢支持
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
TCP/IP三次握手四次挥手
背景 和女朋友异地恋一年多,为了保持感情我提议每天晚上视频聊天一次。 从好上开始,到现在,一年多也算坚持下来了。 问题 有时候聊天的过程中,我的网络或者她的网络可能会不好,视频就会卡住,听不到对方的声音,过一会儿之后才会恢复。 中间双方可能就要不断的确认网络是否恢复,但是有时候会: 她:“你可以听到了吗?” 我:“可以了,你呢?”、 她:“喂喂,你可以听到了吗?” 我:“可以了,我可以听到了,你呢?” 她:“你可以听到了吗?” ..... 这种情况很蛋疼,那么怎样
运维小白
2018/02/06
9980
TCP/IP三次握手四次挥手
面试官:会TCP三次握手,四次挥手吗
在我们日常工作中,无时无刻不在接触HTTP请求,那么HTTP又是基于TCP进行通信的,在面试中面试官经常会问我们,你知道三次握手和四次挥手吗,正在读这篇文章的你,知道吗?不知道的话就跟老哥来一起学习吧!!!
公众号 IT老哥
2020/09/16
1.2K0
面试官:会TCP三次握手,四次挥手吗
TCP三次握手与四次挥手详解
占4个字节。序号使用mod运算。TCP是面向字节流的,在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。故该字段也叫做“报文段序号”。
知忆
2021/06/06
3780
TCP/IP三次握手与四次挥手
TCP/IP三次握手与四次挥手 (1)TCP和UDP对比 1、TCP面向连接(如打电话要先拨号建立连接)。UDP是无连接的,即发送数据之前不需要建立连接; 2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达(进行丢包的重发控制,还可以对次序乱掉的分包进行顺序控    制),UDP尽最大努力交付,即不保证可靠交付; 3、TCP面向字节流。实际上是TCP把数据看成一连串无结构的字节流,UDP是面向报文的; 4、TCP有拥塞控制。UDP没有拥塞控制,因此网络出现拥塞
Mister24
2018/05/14
6250
TCP之三次握手四次挥手
TCP报头中的源端口号和目的端口号同IP数据报中的源IP与目的IP唯一确定一条TCP连接。
程序猿DD
2018/07/31
4870
TCP之三次握手四次挥手
TCP协议三次握手与四次挥手通俗解析
 TCP/IP协议三次握手与四次握手流程解析 一、TCP报文格式 TCP/IP协议的详细信息参看《TCP/IP协议详解》三卷本。下面是TCP报文格式图: 图1 TCP报文格式  上图中有几个字段需要重
用户1214487
2018/01/24
7700
TCP协议三次握手与四次挥手通俗解析
TCP三次握手和四次挥手
(1)序号(sequence number):Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。
云计算小黑
2022/12/28
4780
TCP三次握手和四次挥手
详解TCP三次握手与四次挥手
昨晚模拟面试的时候,发现自己有很多细节没有照顾到位,然后还很飘。 感谢我的老师,九点下班后用他自己宝贵的时间帮我面试。
看、未来
2021/09/18
3230
三次握手与四次挥手
(1)序号(sequence number): Seq序号, 占32位, 用来标识从TCP源端向目的端发送的字节流, 发起方发送数据时对此进行标记.
一个架构师
2022/06/27
2400
三次握手与四次挥手
TCP三次握手&四次挥手
TCP提供一个面向连接的,可靠的字节流服务 面向连接意味着两个使用TCP的应用(通常是一个客户端和服务器)在彼此交换数据之前必须先建立 一个TCP连接。 在一个TCP连接中,仅有两方进行彼此通信
切图仔
2022/09/14
4890
TCP三次握手&四次挥手
关于 TCP 三次握手和四次挥手,满分回答在此
在面试中,计算机网络的 TCP 三次握手和四次挥手是很常见的问题,但是在实际面试中,面试官会更愿意听到怎样的回答呢?详细程度是怎样的?
飞天小牛肉
2021/02/26
1.4K0
关于 TCP 三次握手和四次挥手,满分回答在此
基础巩固——你应该这么理解TCP的三次握手和四次挥手
网络传输层负责最底层的底层链路连接。两台主机之间进行互联,基于网线的物理硬件上的协议。在这个侧面,主机与主机之间只认得硬件mac编码。并不认识IP。
Janti
2018/08/01
5250
基础巩固——你应该这么理解TCP的三次握手和四次挥手
TCP 三次握手和四次挥手
我们知道 UDP 协议乐观且心大,相信网络环境比较健康,数据是可以送达的,即使送达不了也没关系。而 TCP(Transmission Control Protocol,传输控制协议) 就不一样了,它是悲观且严谨,认为网络环境是恶劣的,丢包、乱序、重传和拥塞是常有的事,一言不合就可能送达不了了,因而要从算法层面来保证可靠性。
谛听
2023/10/14
4000
TCP的三次握手和四次挥手
注意: IP层只包含IP地址,端口是在传输层上的,IP+端口号可以唯一表识一个进程(套接字)
承苏凯
2020/07/24
4700
TCP的三次握手和四次挥手
tcp协议的三次握手和四次挥手_tcp为什么是四次挥手
在数据传输过程中,ACK和确认序号是非常重要的,应用程序交给TCP协议发送的数据会暂存在TCP层的发送缓冲区中,发出数据包给对方之后,只有收到对方应答的ACK段才知道该数据包确实发到了对方,可以从发送缓冲区中释放掉了,如果因为网络故障丢失了数据包或者丢失了对方发回的ACK段,经过等待超时后TCP协议自动将发送缓冲区中的数据包重发。
全栈程序员站长
2022/11/10
4950
tcp协议的三次握手和四次挥手_tcp为什么是四次挥手
三次握手 && 四次挥手
TCP是一个面向连接的协议。无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接。
看、未来
2021/10/09
7990
三次握手 && 四次挥手
TCP的三次握手和四次挥手
TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接:
前端老道
2022/03/28
7070
TCP的三次握手和四次挥手
三次握手和四次挥手简单理解
PS:ACK、SYN和FIN这些大写的单词表示标志位,其值要么是1,要么是0;ack、seq小写的单词表示序号。
不会飞的小鸟
2020/07/29
2.4K0
我终于搞懂了TCP的三次握手和四次挥手(图片案例超详解)
1、TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的通信协议,数据在传输前要建立连接,传输完毕后还要断开连接。 2、客户端在收发数据前要使用 connect() 函数和服务器建立连接。建立连接的目的是保证IP地址、端口、物理链路等正确无误,为数据的传输开辟通道。 3、TCP建立连接时要传输三个数据包,俗称三次握手(Three-way Handshaking)
全栈程序员站长
2022/09/05
1.8K0
我终于搞懂了TCP的三次握手和四次挥手(图片案例超详解)
【干货】TCP/IP协议三次握手四次挥手
TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议,在发送数据前,通信双方必须在彼此间建立一条连接。所谓的“连接”,其实是客户端和服务端保存的一份关于对方的信息,如ip地址、端口号等。
未名编程
2024/10/12
1270
【干货】TCP/IP协议三次握手四次挥手
相关推荐
TCP/IP三次握手四次挥手
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文