面试-计算机网络
基础
说下计算机网络体系结构
计算机网络体系结构,一般有三种:OSI 七层模型、TCP/IP 四层模型、五层结构。
简单说,OSI是一个理论上的网络通信模型,TCP/IP是实际上的网络通信模型,五层结构就是为了介绍网络原理而折中的网络通信模型。
OSI 七层模型
OSI 七层模型是国际标准化组织(International Organization for Standardization)制定的一个用于计算机或通信系统间互联的标准体系。
- 应用层:通过应用进程之间的交互来完成特定网络应用,应用层协议定义的是应用进程间通信和交互的规则,常见的协议有:HTTP FTP SMTP SNMP DNS.
- 表示层:数据的表示、安全、压缩。确保一个系统的应用层所发送的信息可以被另一个系统的应用层读取。
- 会话层:建立、管理、终止会话,是用户应用程序和网络之间的接又。
- 运输层:提供源端与目的端之间提供可靠的透明数据传输,传输层协议为不同主机上运行的进程提供逻辑通信。
- 网络层:将网络地址翻译成对应的物理地址,实现不同网络之间的路径选择, 协议有ICMP IGMP IP 等.
- 数据链路层:在物理层提供比特流服务的基础上,建立相邻结点之间的数据链路。
- 物理层:建立、维护、断开物理连接。
TCP/IP 四层模型
- 应用层:对应于 OSI 参考模型的(应用层、表示层、会话层)。
- 传输层: 对应 OSI 的传输层,为应用层实体提供端到端的通信功能,保证了数据包的顺序传送及数据的完整性。
- 网际层:对应于 OSI 参考模型的网络层,主要解决主机到主机的通信问题。
- 网络接口层:与 OSI 参考模型的数据链路层、物理层对应。
五层体系结构
- 应用层:对应于 OSI 参考模型的(应用层、表示层、会话层)。
- 传输层:对应 OSI 参考模型的的传输层
- 网络层:对应 OSI 参考模型的的网络层
- 数据链路层:对应 OSI 参考模型的的数据链路层
- 物理层:对应 OSI 参考模型的的物理层。
说一下每一层对应的网络协议有哪些?
一张表格总结常见网络协议:
那么数据在各层之间是怎么传输的呢?
对于发送方而言,从上层到下层层层包装,对于接收方而言,从下层到上层,层层解开包装。
- 发送方的应用进程向接收方的应用进程传送数据
- AP先将数据交给本主机的应用层,应用层加上本层的控制信息H5就变成了下一层的数据单元
- 传输层收到这个数据单元后,加上本层的控制信息H4,再交给网络层,成为网络层的数据单元
- 到了数据链路层,控制信息被分成两部分,分别加到本层数据单元的首部(H2)和尾部(T2)
- 最后的物理层,进行比特流的传输
这个过程类似写信,写一封信,每到一层,就加一个信封,写一些地址的信息。到了目的地之后,又一层层解封,传向下一个目的地。
网络综合
从浏览器地址栏输入 url 到显示主页的过程?
这道题,大概的过程比较简单,但是有很多点可以细挖:DNS解析、TCP三次握手、HTTP报文格式、TCP四次挥手等等。
- DNS 解析:将域名解析成对应的 IP 地址。
- TCP连接:与服务器通过三次握手,建立 TCP 连接
- 向服务器发送 HTTP 请求
- 服务器处理请求,返回HTTp响应
- 浏览器解析并渲染页面
- 断开连接:TCP 四次挥手,连接结束
我们以输入www.baidu.com 为例:
各个过程都使用了哪些协议?
说说 DNS 的解析过程?
DNS,英文全称是 domain name system ,域名解析系统,它的作用也很明确,就是域名和 IP
相互映射。
DNS 的解析过程如下图:
假设你要查询 http://www.baidu.com 的 IP 地址:
- 首先会查找浏览器的缓存,看看是否能找到www.baidu.com 对应的IP地址,找到就直接返回;否则进行下一步。
- 将请求发往给本地DNS服务器,如果查找到也直接返回,否则继续进行下一步;
- 本地DNS服务器向根域名服务器发送请求,根域名服务器返回负责com 的顶级域名服务器的IP地址的列表。
- 本地DNS服务器再向其中一个负责com 的顶级域名服务器发送一个请求,返回负责baidu.com 的权限域名服务器的IP地址列表。
- 本地DNS服务器再向其中一个权限域名服务器发送一个请求,返回www.baidu.com 所对应的IP地址。
说说 WebSocket 与 Socket 的区别?
- Socket 其实就是等于 IP 地址 + 端又 + 协议。
具体来说,Socket 是一套标准,它完成了对 TCP/IP 的高度封装,屏蔽网络细节,以方便
开发者更好地进行网络编程。
- WebSocket 是一个持久化的协议,它是伴随 H5 而出的协议,用来解决 http 不支持持久化连接的问题。
- Socket 一个是网编编程的标准接口,而 WebSocket 则是应用层通信协议。
说一下你了解的端口及对应的服务?
HTTP
说说 HTTP 常用的状态码及其含义?
- 1XX:信息性状态码
- 2XX:成功状态码
- 3XX:重定向状态码
- 4XX:客户端错误状态码
- 5XX:服务端错误状态码
几个常用的,面试之外,也应该记住:
说一下 301 和 302 的区别?
- 301 :永久性移动,请求的资源已被永久移动到新位置。服务器返回此响应时,会返回新的资源地址。
- 302 :临时性性移动,服务器从另外的地址响应资源,但是客户端还应该使用这个地址。
HTTP 有哪些请求方式?
其中,POST、DELETE、PUT、GET的含义分别对应我们最熟悉的增、删、改、查。
说一下 GET 和 POST 的区别?
可以从以下几个方面来说明GET和POST的区别:
- 从 HTTP 报文层面来看,GET 请求将信息放在 URL,POST 将请求信息放在请求体中。这一点使得 GET 请求携带的数据量有限,因为 URL 本身是有长度限制的,而 POST 请求的数据存放在报文体中,因此对大小没有限制。而且从形式上看,GET 请求把数据放URL 上不太安全,而 POST 请求把数据放在请求体里想比较而言安全些。
- 从数据库层面来看,GET 符合幂等性和安全性,而 POST 请求不符合。这个其实和GET/POST 请求的作用有关。按照 HTTP 的约定,GET 请求用于查看信息,不会改变服务器上的信息;而 POST 请求用来改变服务器上的信息。正因为 GET 请求只查看信息,不改变信息,对数据库的一次或多次操作获得的结果是一致的,认为它符合幂等性。安全性是指对数据库操作没有改变数据库中的数据。
- 从其他层面来看,GET 请求能够被缓存,GET 请求能够保存在浏览器的浏览记录里,GET 请求的 URL 能够保存为浏览器书签。这些都是 POST 请求所不具备的。缓存是 GET请求被广泛应用的根本,他能够被缓存也是因为它的幂等性和安全性,除了返回结果没有其他多余的动作,因此绝大部分的 GET 请求都被 CDN 缓存起来了,大大减少了 Web 服务器的负担。
GET 的长度限制是多少?
HTTP中的GET方法是通过URL传递数据的,但是URL本身其实并没有对数据的长度进行限制,真正限制GET长度的是浏览器。
例如IE浏览器对URL的最大限制是 2000 多个字符,大概2kb左右,像Chrome、Firefox等浏览器支持的URL字符数更多,其中FireFox中URL的最大长度限制是 65536 个字符,Chrome则是8182 个字符。
这个长度限制也不是针对数据部分,而是针对整个URL。
HTTP 请求的过程与原理?
HTTP协议定义了浏览器怎么向服务器请求文档,以及服务器怎么把文档传给浏览器。
- 每个服务器都有一个进程,它不断监听TCP的端口 80 ,以便发现是否有浏览器向它发出连接建立请求
- 监听到连接请求,就会建立TCP连接
- 浏览器向服务器发出浏览某个页面的请求,服务器接着就返回所请求的页面作为响应
- 最后,释放TCP连接
在浏览器和服务器之间的请求和响应的交互,必须按照规定的格式和遵循一定的规则,这些格式和规则就是超文本传输协议HTTP。
PS:这道题和上面浏览器输入网址发生了什么那道题大差不差。
说一下HTTP的报文结构?
HTTP报文有两种,HTTP请求报文和HTTP响应报文:
HTTP请求报文
HTTP 请求报文的格式如下:
1 | GET / HTTP/1.1 |
HTTP 请求报文的第一行叫做请求行,后面的行叫做首部行,首部行后还可以跟一个实体主体。请求首部之后有一个空行,这个空行不能省略,它用来划分首部与实体。
请求行包含三个字段:
- 方法字段:包括POST、GET等请方法。
- URL 字段
- HTTP 版本字段。
HTTP 响应报文
HTTP 响应报文的格式如下:
1 | HTTP/1.0 200 OK |
HTTP 响应报文的第一行叫做 状态行 ,后面的行是 首部行 ,最后是 实体主体 。
状态行 包含了三个字段:协议版本字段、状态码和相应的状态信息。
实体部分 是报文的主要部分,它包含了所请求的对象。
首部行 首部可以分为四种首部,请求首部、响应首部、通用首部和实体首部。通用首部和实体首部在请求报文和响应报文中都可以设置,区别在于请求首部和响应首部。
常见的请求首部有 Accept 可接收媒体资源的类型、Accept-Charset 可接收的字符集、Host 请求的主机名。
常见的响应首部有 ETag 资源的匹配信息,Location 客户端重定向的 URI。
常见的通用首部有 Cache-Control 控制缓存策略、Connection 管理持久连接。
常见的实体首部有 Content-Length 实体主体的大小、Expires 实体主体的过期时间、Last-Modified 资源的最后修改时间。
URI 和 URL 有什么区别?
- URI,统一资源标识符(Uniform Resource Identifier, URI),标识的是We b上每一种可用的资源,如 HTML文档、图像、视频片段、程序等都是由一个URI进行标识的。
- URL,统一资源定位符(Uniform Resource Location),它是URI的一种子集,主要作用是提供资源的路径。
它们的主要区别在于,URL除了提供了资源的标识,还提供了资源访问的方式。这么比喻,URI 像是身份证,可以唯一标识一个人,而 URL 更像一个住址,可以通过 URL 找到这个人——人类住址协议://地球/中国/北京市/海淀区/xx职业技术学院/14号宿舍楼/525号寝/张三.男。
说下 HTTP/1.0,1.1,2.0 的区别?
关键需要记住 HTTP/1.0 默认是短连接,可以强制开启,HTTP/1.1 默认长连接,HTTP/2.0 采用多路复用 。
HTTP/1.0
- 默认使用短连接,每次请求都需要建立一个 TCP 连接。它可以设置Connection:keep-alive 这个字段,强制开启长连接。
HTTP/1.1
- 引入了持久连接,即 TCP 连接默认不关闭,可以被多个请求复用。
- 分块传输编码,即服务端每产生一块数据,就发送一块,用” 流模式” 取代” 缓存模式”。
- 管道机制,即在同一个 TCP 连接里面,客户端可以同时发送多个请求。
HTTP/2.0
- 二进制协议,1.1 版本的头信息是文本(ASCII 编码),数据体可以是文本或者二进制;2.0 中,头信息和数据体都是二进制。
- 完全多路复用,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应。
- 报头压缩,HTTP 协议不带有状态,每次请求都必须附上所有信息。Http/2.0 引入了头信息压缩机制,使用 gzip 或 compress 压缩后再发送。
- 服务端推送,允许服务器未经请求,主动向客户端发送资源。
HTTP/3了解吗?
HTTP/3主要有两大变化, 传输层基于UDP 、使用 QUIC保证UDP可靠性 。
HTTP/2存在的一些问题,比如重传等等,都是由于TCP本身的特性导致的,所以HTTP/3在QUIC的基础上进行发展而来,QUIC(Quick UDP Connections)直译为快速UDP网络连接,底层使用UDP进行数据传输。
HTTP/3主要有这些特点:
- 使用UDP作为传输层进行通信
- 在UDP的基础上QUIC协议保证了HTTP/3的安全性,在传输的过程中就完成了TLS加密握手
- HTTPS 要建立一个连接,要花费 6 次交互,先是建立三次握手,然后是 TLS/1.3 的三次握手。QUIC 直接把以往的 TCP 和 TLS/1.3 的 6 次交互合并成了 3 次,减少了交互次数。
- QUIC 有自己的一套机制可以保证传输的可靠性的。当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响。
我们拿一张图看一下HTTP协议的变迁:
HTTP 如何实现长连接?在什么时候会超时?
什么是 HTTP 的长连接?
HTTP 分为长连接和短连接,本质上说的是 TCP 的长短连接。TCP 连接是一个双向的通
道,它是可以保持一段时间不关闭的,因此 TCP 连接才具有真正的长连接和短连接这一说
法。TCP 长连接可以复用一个 TCP 连接,来发起多次的 HTTP 请求,这样就可以减少资源消
耗,比如一次请求 HTML,如果是短连接的话,可能还需要请求后续的 JS/CSS。
如何设置长连接?
通过在头部(请求和响应头)设置 Connection 字段指定为keep-alive,HTTP/1.0 协议支
持,但是是默认关闭的,从 HTTP/1.1 以后,连接默认都是长连接。
在什么时候会超时呢?
- HTTP 一般会有 httpd 守护进程,里面可以设置 keep-alive timeout,当 tcp 连接闲置超过这个时间就会关闭,也可以在 HTTP 的 header 里面设置超时时间
- TCP 的 keep-alive 包含三个参数,支持在系统内核的 net.ipv4 里面设置;当 TCP 连接之后,闲置了 tcp_keepalive_time,则会发生侦测包,如果没有收到对方的 ACK,那么会每隔 tcp_keepalive_intvl 再发一次,直到发送了 tcp_keepalive_probes,就会丢弃该连接。
1 | tcp_keepalive_intvl = 15 |
说说HTTP 与 HTTPS 有哪些区别?
- HTTP 是超文本传输协议,信息是明文传输,存在安全风险的问题。HTTPS 则解决 HTTP不安全的缺陷,在TCP 和 HTTP 网络层之间加入了 SSL/TLS 安全协议,使得报文能够加密传输。
- HTTP 连接建立相对简单, TCP 三次握手之后便可进行 HTTP 的报文传输。而 HTTPS 在TCP 三次握手之后,还需进行 SSL/TLS 的握手过程,才可进入加密报文传输。
- HTTP 的端又号是 80 ,HTTPS 的端又号是 443 。
- HTTPS 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的。
为什么要用HTTPS?解决了哪些问题?
因为HTTP 是明文传输,存在安全上的风险:
- 窃听风险 ,比如通信链路上可以获取通信内容,用户账号被盗。
- 篡改风险 ,比如强制植入垃圾广告,视觉污染。
- 冒充风险 ,比如冒充淘宝网站,用户金钱损失。
所以引入了HTTPS,HTTPS 在 HTTP 与 TCP 层之间加入了 SSL/TLS 协议,可以很好的解决了这些风险:
- 信息加密:交互信息无法被窃取。
- 校验机制:无法篡改通信内容,篡改了就不能正常显示。
- 身份证书:能证明淘宝是真淘宝。
所以SSL/TLS 协议是能保证通信是安全的。
HTTPS工作流程是怎样的?
这道题有几个要点: 公私钥、数字证书、加密、对称加密、非对称加密 。
HTTPS 主要工作流程:
客户端发起 HTTPS 请求,连接到服务端的 443 端口。
服务端有一套数字证书(证书内容有公钥、证书颁发机构、失效日期等)。
服务端将自己的数字证书发送给客户端(公钥在证书里面,私钥由服务器持有)。
客户端收到数字证书之后,会验证证书的合法性。如果证书验证通过,就会生成一个随机的对称密钥,用证书的公钥加密。
客户端将公钥加密后的密钥发送到服务器。
服务器接收到客户端发来的密文密钥之后,用自己之前保留的私钥对其进行非对称解密,解密之后就得到客户端的密钥,然后用客户端密钥对返回数据进行对称加密,酱紫传输的数据都是密文啦。
服务器将加密后的密文返回到客户端。
客户端收到后,用自己的密钥对其进行对称解密,得到服务器返回的数据。
这里还画了一张更详尽的图:
客户端怎么去校验证书的合法性?
首先,服务端的证书从哪来的呢?
为了让服务端的公钥被大家信任,服务端的证书都是由 CA (Certificate Authority,证书认证机构)签名的,CA就是网络世界里的公安局、公证中心,具有极高的可信度,所以由它来给各个公钥签名,信任的一方签发的证书,那必然证书也是被信任的。
CA 签发证书的过程,如上图左边部分:
- 首先 CA 会把持有者的公钥、用途、颁发者、有效时间等信息打成一个包,然后对这些信息进行 Hash 计算,得到一个 Hash 值;
- 然后 CA 会使用自己的私钥将该 Hash 值加密,生成 Certificate Signature,也就是 CA 对证书做了签名;
- 最后将 Certificate Signature 添加在文件证书上,形成数字证书;
客户端校验服务端的数字证书的过程,如上图右边部分:
- 首先客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1;
- 通常浏览器和操作系统中集成了 CA 的公钥信息,浏览器收到证书后可以使用 CA 的公钥解密 Certificate
- Signature 内容,得到一个 Hash 值 H2 ;
- 最后比较 H1 和 H2,如果值相同,则为可信赖的证书,否则则认为证书不可信。
假如在HTTPS的通信过程中,中间人篡改了证书原文,由于他没有CA机构的私钥,所以CA公钥解密的内容就不一致。
如何理解 HTTP 协议是无状态的?
这个无状态的的状态值的是什么?是客户端的状态,所以字面意思,就是HTTP协议中服务端不会保存客户端的任何信息。
比如当浏览器第一次发送请求给服务器时,服务器响应了;如果同个浏览器发起第二次请求给服务器时,它还是会响应,但是呢,服务器不知道你就是刚才的那个浏览器。
那有什么办法记录状态呢?
主要有两个办法,Session和Cookie。
说说Session 和 Cookie 有什么联系和区别?
先来看看什么是 Session 和 Cookie :
- Cookie 是保存在客户端的一小块文本串的数据。客户端向服务器发起请求时,服务端会向客户端发送一个 Cookie,客户端就把 Cookie 保存起来。在客户端下次向同一服务器再发起请求时,Cookie 被携带发送到服务器。服务端可以根据这个Cookie判断用户的身份和状态。
- Session 指的就是服务器和客户端一次会话的过程。它是另一种记录客户状态的机制。不同的是cookie保存在客户端浏览器中,而session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上,这就是session。客户端浏览器再次访问时只需要从该session中查找用户的状态。
Session 和 Cookie 到底有什么不同呢?
- 存储位置不一样,Cookie 保存在客户端,Session 保存在服务器端。
- 存储数据类型不一样,Cookie 只能保存ASCII,Session可以存任意数据类型,一般情况下我们可以在 Session 中保持一些常用变量信息,比如说 UserId 等。
- 有效期不同,Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session一般有效时间较短,客户端关闭或者 Session 超时都会失效。
- 隐私策略不同,Cookie 存储在客户端,比较容易遭到不法获取,早期有人将用户的登录名和密码存储在 Cookie 中导致信息被窃取;Session 存储在服务端,安全性相对 Cookie 要好一些。
- 存储大小不同, 单个Cookie保存的数据不能超过4K,Session可存储数据远高于 Cookie。
Session 和 Cookie有什么关联呢?
可以使用Cookie记录Session的标识。
用户第一次请求服务器时,服务器根据用户提交的信息,创建对应的 Session,请求返回时将此 Session 的唯一标识信息 SessionID 返回给浏览器,浏览器接收到服务器返回的 SessionID 信息后,会将此信息存入 Cookie 中,同时 Cookie 记录此 SessionID 是属于哪个域名。
当用户第二次访问服务器时,请求会自动判断此域名下是否存在 Cookie 信息,如果存在,则自动将 Cookie 信息也发送给服务端,服务端会从 Cookie 中获取 SessionID,再根据 SessionID 查找对应的 Session 信息,如果没有找到,说明用户没有登录或者登录失效,如果找到 Session 证明用户已经登录可执行后面操作。
分布式环境下Session怎么处理呢?
分布式环境下,客户端请求经过负载均衡,可能会分配到不同的服务器上,假如一个用户的请求两次没有落到同一台服务器上,那么在新的服务器上就没有记录用户状态的Session。
这时候怎么办呢?
可以使用Redis等分布式缓存来存储Session,在多台服务器之间共享。
客户端无法使用Cookie怎么办?
有可能客户端无法使用Cookie,比如浏览器禁用Cookie,或者客户端是安卓、IOS等等。
这时候怎么办?SessionID怎么存?怎么传给服务端呢?
首先是SessionID的存储,可以使用客户端的本地存储,比如浏览器的sessionStorage。
接下来怎么传呢?
- 拼接到URL里:直接把SessionID作为URL的请求参数
- 放到请求头里:把SessionID放到请求的Header里,比较常用。
TCP
详细说一下 TCP 的三次握手机制
TCP提供面向连接的服务,在传送数据前必须建立连接,TCP连接是通过三次握手建立的。
三次握手的过程:
- 最开始,客户端和服务端都处于CLOSE状态,服务端监听客户端的请求,进入LISTEN状态
- 客户端发送连接请求,第一次握手 (SYN=1, seq=x),发送完毕后,客户端就进入SYN_SENT(同步已发送) 状态
- 服务端确认连接,第二次握手 (SYN=1, ACK=1, seq=y, ACKnum=x+1), 发送完毕后,服
务器端就进入 SYN_RCV (同步已接受)状态。 - 客户端收到服务端的确认之后,再次向服务端确认,这就是第三次握手 (ACK=1,ACKnum=y+1),发送完毕后,客户端进入 ESTABLISHED (连接已建立)状态,当服务器端接收到这个包时,也进入 ESTABLISHED 状态。
TCP 握手为什么是三次,为什么不能是两次?不能是四次?
为什么不能是两次?
- 为了防止服务器端开启一些无用的连接增加服务器开销
- 防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
由于网络传输是有延时的(要通过网络光纤和各种中间代理服务器),在传输的过程中,比如客户端发起了 SYN=1
的第一次握手。
如果服务器端就直接创建了这个连接并返回包含 SYN
、ACK
和 Seq
等内容的数据包给客户端,这个数据包因为网络传输的原因丢失了,丢失之后客户端就一直没有接收到服务器返回的数据包。
如果没有第三次握手告诉服务器端客户端收的到服务器端传输的数据的话,服务器端是不知道客户端有没有接收到服务器端返回的信息的。
服务端就认为这个连接是可用的,端口就一直开着,等到客户端因超时重新发出请求时,服务器就会重新开启一个端口连接。这样一来,就会有很多无效的连接端口白白地开着,导致资源的浪费。
还有一种情况是已经失效的客户端发出的请求信息,由于某种原因传输到了服务器端,服务器端以为是客户端发出的有效请求,接收后产生错误。
所以我们需要“第三次握手”来确认这个过程:
通过第三次握手的数据告诉服务端,客户端有没有收到服务器”第二次握手”时传过去的数据,以及这个连接的序号是不是有效的。若发送的这个数据是“收到且没有问题”的信息,接收后服务器就正常建立TCP连接,否则建立TCP连接失败,服务器关闭连接端口。由此减少服务器开销和接收到失效请求发生的错误。
为什么不是四次?
简单说,就是三次挥手已经足够创建可靠的连接,没有必要再多一次握手导致花费更多的时间建立连接。
三次握手中每一次没收到报文会发生什么情况?
第一次握手服务端未收到SYN报文
服务端不会进行任何的动作,而客户端由于一段时间内没有收到服务端发来的确认报文,等待一段时间后会重新发送SYN
报文,如果仍然没有回应,会重复这个过程,直到发送次数超过最大重传次数限制,就会返回连接建立失败。
第二次握手客户端未收到服务端响应的ACK报文
客户端会继续重传,直到次数限制;而服务端此时会阻塞在accept()
处,等待客户端发送ACK报文
第三次握手服务端为收到客户端发送过来的ACK报文
服务端同样会采用类似客户端的超时重传机制,如果重试次数超过限制,则accept()
调用返回-1,服务端建立连接失败;而此时客户端认为自己已经建立连接成功,因此开始向服务端发送数据,但是服务端的accept()
系统调用已经返回,此时不在监听状态,因此服务端接收到客户端发送来的数据时会发送RST
报文给客户端,消除客户端单方面建立连接的状态。
第二次握手传回了ACK,为什么还要传回SYN?
- ACK是为了告诉客户端传来的数据已经接收无误。
- 而传回SYN是为了告诉客户端,服务端响应的确实是客户端发送的报文。
第3次握手可以携带数据吗?
第3次握手是可以携带数据的。
此时客户端已经处于ESTABLISHED
状态。对于客户端来说,它已经建立连接成功,并且确认服务端的接收和发送能力是正常的。
第一次握手不能携带数据是出于安全的考虑,因为如果允许携带数据,攻击者每次在SYN
报文中携带大量数据,就会导致服务端消耗更多的时间和空间去处理这些报文,会造成CPU和内存的消耗。
说说半连接队列和SYN Flood攻击的关系?
什么是半连接队列?
TCP
进入三次握手前,服务端会从CLOSED
状态变为LISTEN
状态,同时在内部创建了两个队列;半连接队列(SYN队列)和**全连接队列(ACCEPT 队列)**。
顾名思义,半连接队列存放的是三次握手未完成的连接,全连接队列存放的是完成三次握手的连接。
TCP
三次握手时,客户端发送SYN
到服务端,服务端收到之后,便回复ACK
和SYN
,状态由LISTEN
变为SYN_RCVD
,此时这个连接就被推入了SYN队列
,即半连接队列。- 当客户端回复
ACK
,服务端接收后,三次握手就完成了。这时连接会等待被具体的应用取走,在被取走之前,它被推入ACCEPT队列
,即全连接队列。
什么是SYN Flood ?
SYN Flood
是一种典型的DDos攻击
,它在短时间内,伪造**==不存在的IP地址==**,向服务器发送大量SYN报文
。当服务器回复SYN+ACK
报文后,不会收到ACK回应报文
,那么SYN队列
里的连接旧不会出对队,久而久之就会占满服务端的SYN 接收队列(半连接队列)
,使得服务器不能为正常用户服务。
那有什么应对方案呢?
主要有syn cookie
和 SYN Proxy
防火墙等。
syn cookie
:在收到SYN包
后,服务器根据一定的方法,以数据包的源地址、端口等信息为参数计算出一个cookie
值作为自己的SYNACK包
的序列号,回复SYN+ACK
后,服务器并不立即分配资源进行处理,等收到发送方的ACK包
后,重新根据数据包的源地址、端口计算该包中的确认序列号是否正确,如果正确则建立连接,否则丢弃该包。SYN Proxy
防火墙︰服务器防火墙会对收到的每一个SYN报文
进行代理和回应,并保持半连接。等发送方将ACK包返回后,再重新构造SYN包发到服务器,建立真正的TCP连接。
说说TCP四次挥手的过程?
PS:问完三次握手,常常也会顺道问问四次挥手,所以也是必须掌握知识点。
TCP四次挥手过程:
- 数据传输结束之后,通信双方都可以主动发起断开连接请求,这里假定客户端发起
- 客户端发送释放连接报文,第一次挥手
(FIN=1,seq=u)
,发送完毕后,客户端进入FIN_WAIT_1
状态。 - 服务端发送确认报文,第二次挥手
(ACK=1,ack=u+1,seq =v)
,发送完毕后,服务器端进入CLOSE_WAIT
状态,客户端接收到这个确认包之后,进入FIN_WAIT_2
状态。 - 服务端发送释放连接报文,第三次挥手
(FIN=1,ACK1,seq=w,ack=u+1)
,发送完毕后,服务器端进入LAST_ACK
状态,等待来自客户端的最后一个ACK
。 - 客户端发送确认报文,第四次挥手
(ACK=1,seq=u+1 ,ack=w+1)
,客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入TIME_WAIT
状态,等待了某个固定时间(两个最大段生命周期,2MSL
,2 Maximum Segment Lifetime
)之后﹐没有收到服务器端的ACK
,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入CLOSED
状态。服务器端接收到这个确认包之后,关闭连接,进入CLOSED
状态。
TCP挥手为什么需要四次呢?
再来回顾下四次挥手双方发FIN包
的过程,就能理解为什么需要四次了。
- 关闭连接时,客户端向服务端发送
FIN
时,仅仅表示客户端不再发送数据了但是还能接收数据。 - 服务端收到客户端的
FIN报文
时,先回一个ACK应答报文
,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送FIN报文
给客户端来表示同意现在关闭连接。
从上面过程可知,服务端通常需要等待完成数据的发送和处理,所以服务端的ACK
和FIN
一般都会分开发送,从而比三次握手导致多了一次。
TCP四次挥手过程中,为什么需要等待2MSL,才进入CLOSED关闭状态?
为什么需要等待?
1.为了保证客户端发送的最后一个ACK报文段能够到达服务端。这个ACK报文段
有可能丢失,因而使处在LAST-ACK状态
的服务端就收不到对已发送的FIN + ACK 报文段
的确认。服务端会超时重传这个FIN+ACK报文段
,而客户端就能在2MSL
时间内(超时+1MSL传输)收到这个重传的FIN+ACK报文段
。接着客户端重传一次确认,重新启动2MSL
计时器。最后,客户端和服务器都正常进入到CLOSED
状态。
2.防止已失效的连接请求报文段出现在本连接中。客户端在发送完最后一个ACK报文段
后,再经过时间2MSL
,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样就可以使下一个连接中不会出现这种旧的连接请求报文段。
为什么等待的时间是2MSL?
MSL
是 Maximum Segment Lifetime
,报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
TIME_WAIT
等待2倍的MSL
,比较合理的解释是︰网络中可能存在来自发送方的数据包,当这些发送方的数据包被接收方处理后口会向对方发送响应,所以一来一回需要等待2倍的时间。
比如如果被动关闭方没有收到断开连接的最后的ACK报文
,就会触发超时重发Fin报文
,另一方接收到FIN
后,会重发ACK
给被动关闭方,一来一去正好2个MSL
。
保活计时器有什么用?
除时间等待计时器外,TCP
还有一个保活计时器(keepalive timer)
。
设想这样的场景:客户已主动与服务器建立了TCP
连接。但后来客户端的主机突然发生故障。显然,服务器以后就不能再收到客户端发来的数据。因此,应当有措施使服务器不要再白白等待下去。这就需要使用保活计时器了。
服务器每收到一次客户端的数据,就重新设置保活计时器,时间的设置通常是两个小时。若两个小时都没有收到客户端的数据,服务端就发送一个探测报文段,以后则每隔75秒钟
发送一次。若连续发送10个探测报文段
后仍然无客户端的响应,服务端就认为客户端出了故障,接着就关闭这个连接。
CLOSE-WAIT和TIME-WAIT的状态和意义?
CLOSE-WAIT状态有什么意义?
服务端收到客户端关闭连接的请求并确认之后,就会进入CLOSE-WAIT
状态。此时服务端可能还有一些数据没有传输完成,因此不能立即关闭连接,而CLOSE-WAIT
状态就是为了保证服务端在关闭连接之前将待发送的数据处理完。
TIME-WAIT有什么意义?
TIME-WAIT
状态发生在第四次挥手,当客户端向服务端发送ACK确认报文
后进入TIME-WAIT
状态。
它存在的意义主要是两个:
- 防止旧连接的数据包
如果客户端收到服务端的FIN报文
之后立即关闭连接,但是此时服务端对应的端口并没有关闭,如果客户端在相同端口建立新的连接,可能会导致新连接收到旧连接残留的数据包,导致不可预料的异常发生。
- 保证连接正确关闭
假设客户端最后一次发送的ACK包
在传输的时候丢失了,由于TCP
协议的超时重传机制,服务端将重发FIN
报文,如果客户端没有维持TIME-WAIT
状态而直接关闭的话,当收到服务端重新发送的FIN包时,客户端就会使用RST包
来响应服务端,导致服务端以为有错误发生,然而实际关闭连接过程是正常的。
TIME_WAIT状态过多会导致什么问题?怎么解决?
TIME_WAIT状态过多会导致什么问题?
如果服务器有处于TIME-WAIT
状态的TCP
,则说明是由服务器方主动发起的断开请求。
过多的TIME-WAIT
状态主要的危害有两种:
- 第一是内存资源占用;
- 第二是对端口资源的占用,一个TCP连接至少消耗一个本地端口;
怎么解决TIME_WAIT状态过多?
- 服务器可以设置
SO_REUSEADDR
套接字来通知内核,如果端口被占用,但是TCP
连接位于TIME_WAIT
状态时可以重用端口。 - 还可以使用长连接的方式来减少
TCP
的连接和断开,在长连接的业务里往往不需要考虑TIME_WAIT
状态。
说说TCP报文首部的格式?
看一下TCP报文首部的格式:
- 16位端口号︰源端口号,主机该报文段是来自哪里;目标端口号,要传给哪个上层协议或应用程序
- 32位序号∶一次TCP通信(从TCP连接建立到断开)过程中某一个传输方向上的字节流的每个字节的编号。
- 32位确认号︰用作对另一方发送的tcp报文段的响应。其值是收到的TCP报文段的序号值加1。
- 4位首部长度︰表示 tcp头部有多少个32bit字(4字节)。因为4位最大能标识15,所以TCP头部最长是60字节。
- 6位标志位︰URG(紧急指针是否有效),ACk(表示确认号是否有效),PST(缓冲区尚未填满),RST(表示要求对方重新建立连接),SYN(建立连接消息标志接),FIN(表示告知对方本端要关闭连接了)
- 16位窗口大小︰是TCP流量控制的一个手段。这里说的窗口,指的是接收通告窗口。它告诉对方本端的TCP接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度。
- 16位校验和︰由发送端填充,接收端对TCP报文段执行CRC算法以检验TCP报文段在传输过程中是否损坏。注意,这个校验不仅包括TCP头部,也包括数据部分。这也是TCP可靠传输的一个重要保障。
- 16位紧急指针:一个正的偏移量。它和序号字段的值相加表示最后一个紧急数据的下一字节的序号。因此,确切地说,这个字段是紧急指针相对当前序号的偏移,不妨称之为紧急偏移。TCP的紧急指针是发送端向接收端发送紧急数据的方法。
TCP是如何保证可靠性的?
TCP主要提供了检验和、序列号/确认应答、超时重传、最大消息长度、滑动窗口控制等方法实现了可靠性传输。
1.连接管理:TCP
使用三次握手和四次挥手保证可靠地建立连接和释放连接,这里就不用多说了。
2.校验和:TCP
将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果接收端的检验和有差错,TCP将丢弃这个报文段和不确认收到此报文段。
3.序列号/确认应答:TCP
给发送的每一个包进行编号,接收方会对收到的包进行应答,发送方就会知道接收方是否收到对应的包,如果发现没有收到,就会重发,这样就能保证数据的完整性。就像老师上课,会问一句,这一章听懂了吗?没听懂再讲一遍。
4.流量控制:TCP
连接的每一方都有固定大小的缓冲空间,TCP
的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP
使用的流量控制协议是可变大小的滑动窗口协议。**(TCP利用滑动窗口实现流量控制)**
5.最大消息长度∶在建立TCP连接
的时候,双方约定一个最大的长度(MSS)
作为发送的单位,重传的时候也是以这个单位来进行重传。理想的情况下是该长度的数据刚好不被网络层分块。
6、超时重传:超时重传是指发送出去的数据包到接收到确认包之间的时间,如果超过了这个时间会被认为是丢包了,需要重传。
7.拥塞控制:如果网络非常拥堵,此时再发送数据就会加重网络负担,那么发送的数据段很可能超过了最大生存时间也没有到达接收方,就会产生丢包问题。为此TCP
引入慢启动机制,先发出少量数据,就像探路一样,先摸清当前的网络拥堵状态后,再决定按照多大的速度传送数据。