Python常见面试题:TCP 协议中的三次握手与四次挥手相关概念详解
今天来聊聊Python常见面试题中面试频率特别高的一个题目:TCP 协议中的三次握手与四次挥手。
涉及到的知识点有:
1、TCP、UDP 协议的区别
2、TCP 头部结构
3、三次握手与四次挥手过程详解
4、什么是 TIME_WATI 状态
内容稍微有点多,大家耐心些看完!
一、TCP、UDP 协议的区别
在介绍这两者的区别之前,我们要需要了解一个概念:TCP/IP 协议族。定义如下:
目前 Internet(因特网)使用的主流协议族是 TCP/IP 协议族,它是一个分层、多协议的通信体系 《Linux高性能编程》
提取关键词:分层、多协议和通信。也就是说,它有多个层次,每个层次有不同的协议,这些层次之间通过协议相互协作,最终达到网络通信的目的。
说到分层,应该不会很陌生,TCP/IP 协议族是一个四层协议系统,自底而上分别是:数据链接层、网络层、传输层、应用层。我们这里要说到的 TCP 和 UDP 协议属于传输层。(各层的作用及相关协议这里暂时先不做介绍)
下面我们回到标题:TCP、UDP 协议的区别,总结起来这个问题的答案要点如下:
1、首页它们俩都是传输层的协议,而所谓“传输层”,它是为两台主机提供端到端的通信,即从 A <-> B 。
2、TCP 协议可靠,UDP 协议不可靠。可靠即指数据由 A 发送到 B,是否能确保数据真的有送达到 B。TCP 协议使用 超时重传、数据确认等方式来确保数据包被正确地发送至目的端,而 UDP 协议无法保证数据从发送端正确传送到目的端,如果数据在传输过程中丢失、或者目的端通过数据检验发现数据错误,则 UDP 协议只是简单地通知应用程序发送失败,对于 TCP 协议拥有的超时重传、数据确认等需要应用程序自己来处理这些逻辑。
3、TCP 是面向连接的,UDP 是无连接的。这也比较好理解,因为 TCP 连接才需要“三次握手,四次挥手”。
4、TCP 服务是基于流的,而 UDP 是基于数据报的,基于流的数据没有边界(长度)限制,而基于数据报的服务,每个 UDP 数据报都有一个长度,接收端必须以该长度为最小单位将其所有内容一次性读出。
5、当发送方多次执行写操作时,TCP 模块会先将这些数据放入 TCP 发送缓冲区中,当 TCP 模块真正开始发送数据时,发送缓冲区中这些等待发送的数据可能被封装成一个或多个 TCP 报文段发出,因此,TCP 模块发出的 TCP 报文段的个数与应用程序执行的写操作次数是没有固定数量关系的。同样,当接收端收到一个或多个 TCP 报文段后,TCP 模块将这些数据按照序号(序号说明见下面 的 TCP 头部结构)依次放入 TCP 接收缓冲区中,并通知应用程序读取数据。接收端可选择一次或者分多次将数据从缓冲区中读出(这取决于用户指定的应用程序读缓冲区的大小)。因此,接收端读取数据的次数与发送端发出多少个报文段个数也没有固定的数量关系。总结来说,即**对于 TCP 连接,发送端执行的写操作次数与接收端执行的读操作次数之间没有任何数据关系,这也是基于流服务的特点。**而对于 UDP 服务,发送端每执行一次写操作,就会将其封装成一个 UDP 数据报并发送之,同时接收端必须根据发送的进行读,否则就会丢包。因此,对于 UDP 连接,发送端写的次数据与读的次数是一致的,这也是基于数据报的服务的特点。
6、TCP 的连接是一对一的,所以如果是基于广播或者多播的的应用程序不能使用 TCP,而 UDP 则非常适合广播和多播。
总结一句定义:
TCP 协议(Transmission Control Protocal,传输控制协议)为应用层提供可靠的、面向连接的、基于流的服务。而 UDP 协议(User Datagram Protocal,用户数据报协议)则与 TCP 协议完全相反,它为应用层提供不可靠、无连接和基于数据报的服务。
二、TCP 头部结构
TCP 报文结构分为头部部分和数据部分,为什么需要了解 TCP 头部结构,因为在后面“三次握手与四次挥手”里会用到头部结构里的标志位。简单了解下对理解后面的过程有一定的好处。
下面一一说明每个的作用:
16位源端口号与目的端口号,这个比较好理解,就不过多解释。
32位序号:在建立连接(或者关闭)的过程,这个序号是用来做占位,当 A 发送连接请求到 B,这个时候会带上一个序号(随机值,称为 ISN),而 B 确认连接后,会把这个序号 +1 返回,同时带上自己的充号。当建立连接后,该序号为生成的随机值 ISN 加上该段报文段所携带的数据的第一个字节在整个字节流中的偏移量。比如,某个 TCP 报文段发送的数据是字节流中的第 100 ~ 200 字节,那该序号为 ISN + 100。所以总结起来说明建立连接(或者关闭)时,序号的作用是为了占位,而连接后,是为了标记当前数据流的第一个字节。
4位头部长度:标识 TCP 头部有多少个 32 bit 字,因为是 4位,即 TCP 头部最大能表示 15,即最长是 60 字节。即它是用来记录头部的最大长度。
6位标志位,包括:
URG 标志:表示紧急指针是否有效。
ACK 标志:确认标志。通常称携带 ACK 标志的 TCP 报文段为确认报文段。
PSH 标志:提示接收端应该程序应该立即从 TCP 接收缓冲区中读走数据,为接收后续数据腾出空间(如果不读走,数据就会一直在缓冲区内)。
RST 标志:表示要求对方重新建立连接。通常称携带 RST 标志的 TCP 报文段为复位报文段。
SYN 标志:表示请求建立一个连接。通常称携带 SYN 标志的 TCP 报文段称为同步报文段。
FIN 标志:关闭标志,通常称携带 FIN 标志的 TCP 报文段为结束报文段。
这些标志位说明了当前请求的目的,即要干什么。
16 位窗口大小:表示当前 TCP 接收缓冲区还能容纳多少字节的数据,这样发送方就可以控制发送数据的速度,它是 TCP 流量控制的一个手段。
16 位校验和:验证数据是否损坏,通过 CRC 算法检验。这个校验不仅包括 TCP 头部,也包括数据部分。
16 位紧急指针:正的偏移量,它和序号字段的值相加表示最后一个紧急数据的下一字节的序号。TCP 的紧急指针是发送端向接收端发送紧急数据的方法。
TCP 头部选项:可变长的可选信息,这部分最多包含 40 字节,因为 TCP 头部最长是 60 字节,所以固定部分占 20 字节。这里不做详细介绍,可以参考《Linux高性能编程》3.2.2
三、三次握手与四次挥手过程详解
画图
先来解释三次握手过程:
1、发送端发送连接请求,6位标志为 SYN,同时带上自己的序号(此时由于不传输数据,所以不表示字节的偏移量,只是占位),比如是 223。
2、接收端接到请求,表示同意连接,发送同意响应,带上 SYN + ACK 标志位,同时将确认序号为 224(发送端序号加1),并带上自己的序号(此时同样由于不传输数据,所以不表示字节的偏移量,只是占位),比如是 521。
3、发送端接收到确认信息,再发回给接收端,表示我已接受到你的确认信息,此时标志仍为 ACK,确认序号为 522。
涉及到的问题:为什么是三次握手,而不是四次或者两次?
首先解释为什么不是四次。四次的过程是这样的:
发送方:我要连你了。
接收方:好的。
接收方:我准备好了,你连吧。
发送方:好的。
显然接收方准备好连接并同意连接是可以合并的,这样可以提高连接的效率。
再来,我们解释为什么不是两次。其实也比较好理解,我们知道 TCP 是全双工通信的,同时也是可靠的,连接和关闭都是两边都要执行才算真正的完成,同时还需要确保两端都已经执行了连接或者关闭。如果只有两次,过程是这样的:
发送方:我要连你了。
接收方:好的。
很明显,接收方并不知道也不能保证发送方一定接收到 “好的” 这条信息,一旦接收方真的没有收到这条信息,就会出现接收收“单方面连接”的情况,这个时候发送方就会一直重试发送连接请求,直到真正收到 “好的” 这条信息之后才算连接完成。而对于三次,如果发送方没有等待到你回复确认,它是不会真正处于连接状态的,它会重试确认请求。
接着我们来看看四次挥手过程:
1、发送方发送关闭请求,标志位为:FIN,同时也会带上自己的序号(此时同样由于不传输数据,所以不表示字节的偏移量,只是占位)。
2、接收方接到请求后,回复确认:ACK,同时确认序号为请求序号加1。
3、接收方也决定关闭连接,发送关闭通知,标志位为 FIN,同时还会带上第2步中的确认信息,即 ACK,以及确认序号和自己的序号。
4、发送方回复确认信息:ACK,接收方序号加1。
涉及到的问题:为什么需要四次握手,不是三次?
三次的过程是这样的:
发送方:我不再给你发送数据了。
接收方:好的,我也不给你发了。
发送方:好的,拜拜。
这是因为当接收方收到关闭请求后,它能立马响应的就是确认关闭,它这里确认的是接收方的关闭,即发送方不再发数据给接收方了,但他还是可以接收接收方发给他的数据。而接收方是否需要关闭“发送数据给发送方”这条通道,取决于操作系统。操作系统也有可能 sleep 个几秒再关闭,如果合并成三次,就可能造成接收方不能及时收到确认请求,可能造成超时重试等情况。因此需要四次。
四、什么是 TIME_WAIT 状态
首先,我们来看一段代码(说了这么多理论,终于要看点代码了)。这里举一个 python 简单的使用 socket 进行 tcp 通信的示例:
服务端:
socket_server_test.py# -*- coding: utf-8 -*-"""@Time : 2019/6/26 下午4:58@Author : Demon@File : socket_server_test.py@Desc : """import socketHOST = '127.0.0.1' # 标准的回环地址 (localhost)PORT = 9999 # 监听的端口 (非系统级的端口: 大于 1023)s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 第三个参数,如果为0,也不可复用# 第三个如果为1,可以复用# s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)s.bind((HOST, PORT))s.listen()conn, addr = s.accept()with conn: print('Connected by', addr) while True: data = conn.recv(1024) print("data:", data) if data: print("close") s.close() break conn.sendall(data)
客户端:
# -*- coding: utf-8 -*-"""@Time : 2019/6/26 下午4:55@Author : yrr@File : socket_client_test.py@Desc : 测试 self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)"""import socketHOST = '127.0.0.1' # 服务器的主机名或者 IP 地址PORT = 9999 # 服务器使用的端口s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)s.connect((HOST, PORT))s.sendall(b'Hello, world')data = s.recv(1024)print('Received', repr(data))
执行效果:
我们会发现,当我们服务端主动关闭时,如果我们再次运行这个程序,会报错误说端口仍然被占用。这就很奇怪了,明明已经关闭了连接,为什么还会占用着端口呢?我们使用 netstat -an|grep 9999 命令查看,发现当前这个连接处于 TIME_WAIT 状态。
我们来说下 TIME_WAIT 状态。即当一方断开连接后,它并没有直接进入 CLOSED 状态,而是转移到 TIME_WAIT 状态,在这个状态,需要等待 2MSL(Maximum Segment Life,报文段最大生存时间)的时间,才能完全关闭。
涉及问题:
1、为什么需要有 TIME_WAIT 状态存在?
简单来说有两点原因如下:
a. 当最后发送方发出确认信息后,仍然不能保证接收方能收到信息,万一没收到,那接收方就会重试,而此时发送方已经真正关闭了,就接受不到请求了。
b. 如果发送方在发出确认信息后就关闭了,在接收方接到确认信息的过程中,发送方是有可能再次发出连接请求的,那这个时候就乱套了。刚连接完,又收到确认关闭的信息。
2、为什么时长是 2MSL 呢?
这个其实也比较好理解,所以我发送确认信息,到达最长时间是 MSL,而你如果没接受到,再重试,时间最长也是 MSL,那我等 2MSL,如果还没收到请求,证明你真的已经正常收到了。
正因为我们有这个 TIME_WAIT 状态,所以通常我们说是客户端先关闭,一般不会让服务器端先关闭。那如何避免出现关闭后端口被占用的情况(即上面代码示例问题怎么解决)呢?很简单,加一行代码即可实现:
# socket.SO_REUSEADDR 表示 close 后端口可复用s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Python常见面试题中这个三次握手与四次挥手的出题率还是比较高的,包含的知识点也比较多,大家慢慢消化!有哪里不清楚的地方,
转载于:https://www.cnblogs.com/cherry-tang/p/11139746.html
Python常见面试题:TCP 协议中的三次握手与四次挥手相关概念详解相关推荐
- 【转】TCP协议中的三次握手和四次挥手(图解)
建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 先来看看如何建立连接的. 首先Client端发送连接请求报文,Server段接受连接后回复ACK报文,并为这次连接分配资 ...
- Linux疑难杂症解决方案100篇(十九)-什么是TCP协议中的“三次握手,四次挥手”?带你深入探讨下
前言 以下是博主精心整理的专栏,需要的小伙伴可自行订阅. 深度学习100例全系列详细教程 深度学习算法原理介绍及应用案例 tensorflow从入门到精通100讲 深度学习框架TensorFlow的 ...
- 图解TCP协议中的三次握手和四次挥手
最近在复习计算机网络,看到TCP这一章,总结一下. 建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 1.jpg 先来看看如何建立连接的: 2.png 首先Client端 ...
- [转]TCP协议中的三次握手和四次挥手(图解)
本文转自:http://blog.csdn.net/whuslei/article/details/6667471 建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 先来 ...
- TCP协议中的三次握手和四次挥手(图…
http://m.blog.csdn.net/article/details?id=51793861 http://m.blog.csdn.net/article/details?id=6667471
- tcp 协议中发送窗口的大小应该是_TCP 协议中的三次握手与四次挥手
今天来聊聊面试频率特别高的一个题目:TCP 协议中的三次握手与四次挥手.涉及到的知识点有: 1.TCP.UDP 协议的区别 2.TCP 头部结构 3.三次握手与四次挥手过程详解 4.什么是 TIME_ ...
- 【转载】万字详文彻底弄懂TCP协议:从三次握手和四次挥手说起
今日头条 腾讯技术工程 作者:morganhuang,腾讯 IEG 后台开发工程师 说到 TCP 协议,相信大家都比较熟悉了,对于 TCP 协议总能说个一二三来,但是 TCP 协议又是一个非常复杂的协 ...
- tcp协议报文和三次握手与四次挥手
tcp协议: tcp是面向连接.可靠的进程到进程之间的协议.tcp提供全双工服务:即:数据可在同一时间双向传输. tcp报文段首部格式: 各字段含义: 源端口号:16位字段,为发送端进程对应的端口号 ...
- TCP三次握手与四次挥手(详解)
TCP三次握手 一:引出 客户端与服务器之间数据的发送和返回的过程当中需要创建一个叫TCP connection的东西:由于TCP不存在连接的概念,只存在请求和响应,请求和响应都是数据包,它们之间都是 ...
最新文章
- java 启动某个类_java – Spring Boot – 如何指定备用启动类? (多个入口点)
- WebGL Shader 环境搭建
- Java笔记(十九) 反射
- 经典永驻,重温设计模式 |硬核!
- 转-Kafka【第一篇】Kafka集群搭建
- 水题 UVA 1586 - Ancient Cipher化学式分子量计算
- MySQL怎么查游戏内邮件附件_怎么查询游戏mysql账号密码
- Ocata:Packstack Ocata does not configure nova for placement API
- python菜单栏添加子菜单_python添加菜单图文讲解
- ComponentOne Ultimate 2012 v2 新特性
- 国内国外最好的java开发论坛及站点 [转]
- Ghostscript的介绍和移植
- 轻松绘制图像图形!且看Aspose新产品GDI +图形处理API-Aspose.Drawing如何操作!
- 什么是 知足者常乐?
- GRPC Connection Backoff Protocol
- 【正点原子MP157连载】第二十八章 A7和M4联合调试-摘自【正点原子】STM32MP1 M4裸机CubeIDE开发指南
- 看集装箱号码识别技术如何解决港口拥堵
- 精密制造业行业_精密制造业的发展:精密制造业的深度报告
- 如何成为一个漏洞赏金猎人
- java git_Java 实战开发之git环境安装(三)
热门文章
- TCP/IP协议族-----10、搬家IP
- spring mvc绑定对象String转Date解决入参不能是Date的问题
- 关于程序工作者的规划与思考
- Java 中正确获取中文字符串长度
- Flink EventTime和Watermarks原理结合代码分析(转载+解决+精简记录)
- xlwt+xlrd配合使用修改excel表格
- 语义分割和实例分割以及目标检测的区别(转)
- fit,fit_generator的使用区别
- 最速下降法steepest descent详细解释
- 数值方法:插值与多项式逼近