1 四层模型
计算机网络的各层协议及作用?
计算机网络体系可以大致分为一下三种,OSI七层模型、TCP/IP四层模型和五层模型。
- 应用层:决定这次通信的应用类型,比如说FTP、DNS、SMTP等等,同时HTTP协议也属于应用层的范围。通俗来讲,应用层决定这一次通信要干嘛。
- 传输层:传输层提供两台计算机之间的数据传输,传输层中包含着两个很叼的协议,分别是TCP和UDP协议。面试中经常提及的三次握手,四次挥手就是TCP协议的部分内容。
- 网络层:网络层则是用来处理这些流动的数据包,
把相应的数据包路由到指定的地点
,为通信时的网络传输选择传输路线。 - 数据链路层:数据链路层包含了软件与硬件的接口部分,以及各种网络设备的硬件,也就是整个网络通信过程中最底层的基础设施数据链路层通常简称为链路层。
将网络层传下来的IP数据包组装成帧
,并再相邻节点的链路上传送帧。
各层工作机器
- 第一层物理层:包括物理连网媒介 如双绞线、同轴电缆、电缆连线连接器等,计算机连网的基础,在这一层,数据还没有被组织。
- 继器:它的作用是放大信号,补偿信号衰减,支持远距离的通信。
- 集线器:提供信号放大和中转的功能,有信号广播。中继器与集线器的区别在于连接设备的线缆的数量。一个中继器通常只有两个端口,而一个集线器通常有4至20个或更多的端口。
- 第二层数据链路层:它控制网络层与物理层之间的通信。
- 交换机:物理编址、网络拓扑结构、错误校验、帧序列以及流控。
- 网卡:有帧的发送与接收、帧的封装与拆封、介质访问控制、数据的编码与解码以及数据缓存的功能
- 第三层网络层其主要功能是将网络地址翻译成对应的物理地址。
- 路由器(网关):连通不同的网络、选择信息传送的线路。
- 三层交换机有路由功能,一次路由,多次转发。
浏览器中输入URL返回页面过程(一次HTTP请求的过程)?
详细版
- 应用层准备好 请求报文 ,DNS域名解析(域名 www.baidu.com 变为 ip 地址),得到百度的ip地址,并将报文发到传输层。
- 传输层收到报文后,会将请求的数据包进行 拆分,打包 ,在请求报文的基础上,加上一层TCP的首部信息,然后发往网络层。发起 tcp 的三次握手,建立 tcp 连接。
- 到了网络层以后,IP协议就发挥了巨大的作用,IP协议中需要两个比较重要的信息,那就是 ip地址和mac地址 ,加一层IP首部,把数据发到数据链路层。
- ip已经在应用层通过dns解析出来了;
- ARP协议根据ip地址反向查询到目标主机的mac地址。
- 数据包通过数据链路层进行传输
- 请求到达服务器后,先从数据链路层往上走,并验证消去以太网首部信息,在网络层消去IP首部,在传输层消去TCP首部,就像剥洋葱一样一层一层去皮,最后剩下的就请求报文。在应用层对请求做出处理之后,需要对请求返回一个响应。而整个响应的传输过程就和请求一样,一层一层的封装,响应到达客户端时再一层一层的消去首部,最后呈现响应的结果。
简述版
- 应用层准备好 请求报文,DNS域名解析(域名 www.baidu.com 变为 ip 地址),得到百度的ip地址
- 发起 tcp 的三次握手,建立 tcp 连接。浏览器会以一个随机端口(1024-65535)向服务端的 web 程序 80 端口发起 tcp 的连接。
- 建立 tcp 连接后发起 http 请求。
- 服务器响应 http 请求,客户端得到 html 代码。
- 浏览器解析 html 代码,并请求 html 中的资源。
- 浏览器对页面进行渲染,并呈现给用户。
DNS解析过程?
- 浏览器搜索自己的DNS缓存(维护一张域名与IP的对应表);
- 若没有,则搜索操作系统的DNS缓存(维护一张域名与IP的对应表);
- 若没有,则搜索操作系统的hosts文件(维护一张域名与IP的对应表);
- 若都没有,则找 TCP/IP 参数中设置的
首选 dns 服务器
,即本地 dns 服务器(LDNS,一般在城市中离你不远的角落)
。本地dns服务器将解析出的IP返回给用户
,如果还查不到就继续向上查询; - 如果LDNS仍然没有命中,就直接跳到
Root Server 域名服务器
请求解析; 根域名服务器
返回给LDNS一个所查询域
的主域名服务器(gTLD Server,国际顶尖域名服务器,如.com .cn .org等)地址
;- 此时LDNS再发送请求给上一步返回的
gTLD(主域名服务器)
; - 接受请求的
gTLD
查找并返回这个域名对应的Name Server的地址
,这个Name Server就是网站注册的域名服务器
; - Name Server
根据映射关系表找到目标ip
,返回给LDNS; - LDNS把解析的结果返回给用户,用户根据TTL值缓存到本地系统缓存中,域名解析过程至此结束。
ARP & RARP TODO
2 TCP & UDP
UDP 和 TCP 的特点与区别?
- 用户数据报协议 UDP(User Datagram Protocol)
- 无连接的,尽最大可能交付,没有拥塞控制,面向报文(对于应用程序传下来的报文不合并也不拆分,只是添加 UDP 首部),支持一对一、一对多、多对一和多对多的交互通信。
- 传输控制协议 TCP(Transmission Control Protocol)
- 面向连接的,提供可靠交付,有流量控制,拥塞控制,提供全双工通信,面向字节流(把应用层传下来的报文看成字节流,把字节流组织成大小不等的数据块),每一条 TCP 连接只能是点对点的(一对一) 。
UDP 和 TCP 对应的应用场景是什么?
TCP 用于在传输层有必要实现可靠传输的情况,UDP 用于对高速传输和实时性有较高要求的通信。TCP和 UDP 应该根据应用目的按需使用。
TCP 是面向连接,能保证数据的可靠性交付,因此经常用于:
- FTP文件传输
- HTTP / HTTPS
UDP 面向无连接,它可以随时发送数据,再加上UDP本身的处理既简单又高效,因此经常用于:
- 包总量较少的通信,如 DNS 、SNMP等
- 视频、音频等多媒体通信
- 广播通信
TCP协议如何保证可靠性?
TCP主要提供了检验和、序列号/确认应答、超时重传、滑动窗口、拥塞控制和流量控制等方法实现了可靠性传输。
- 检验和:通过检验和的方式,接收端可以检测出来数据是否有差错和异常,假如有差错就会直接丢弃TCP段,重新发送。
- 序列号/确认应答:TCP传输的过程中,每次接收方收到数据后,都会对传输方进行确认应答。也就是发送ACK报文,这个ACK报文当中带有对应的确认序列号,告诉发送方,接收到了哪些数据,下一次的数据从哪里发。
- 流量控制:原理这就是运用TCP报文段中的窗口大小字段来控制,发送方的发送窗口不可以大于接收方发回的窗口大小。
详细讲一下TCP的滑动窗口?
在进行数据传输时,如果传输的数据比较大,就需要拆分为多个数据包进行发送。
TCP 协议需要对数据进行确认后,才可以发送下一个数据包。这样一来,就会在等待确认应答包环节浪费时间。
为了避免这种情况,TCP引入了窗口概念。滑动窗口大小指的是不需要等待确认应答包而可以继续发送数据包的最大值。
从上面的图可以看到滑动窗口左边的是已发送并且被确认的分组,滑动窗口右边是还没有轮到的分组 。
滑动窗口里面也分为两块,一块是已经发送但是未被确认的分组,另一块是窗口内等待发送的分组。随着已发送的分组不断被确认,窗口内等待发送的分组也会不断被发送。整个窗口就会往右移动,让还没轮到的分组进入窗口内。
可以看到滑动窗口起到了一个限流的作用,也就是说当前滑动窗口的大小决定了当前 TCP 发送包的速率,而滑动窗口的大小取决于 拥塞控制窗口 和 流量控制窗口 的两者间的 最小值。
什么是流量控制?
所谓流量控制就是让发送发送速率不要过快,让接收方来得及接收。利用滑动窗口机制就可以实施流量控制。
原理这就是运用TCP报文段中的窗口大小字段来控制,发送方的发送窗口不可以大于接收方发回的窗口大小。
流量控制 和 拥塞控制 的区别?TODO TODO
- 流量控制指接收端的接受能力
- 拥塞控制指根据网络的承载能力来决定发送的数据量
快速重传与超时重传详解
参考:https://blog.csdn.net/IT_Quanwudi/article/details/86603779
详细讲一下拥塞控制?
什么是拥塞:
- 在某段时间内,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种情况就称为拥塞。简单的说拥塞产生的原因有两点:
- 接收方容量不够
- 网络内部有瓶颈
什么是拥塞控制:防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。
TCP 一共使用了四种算法来实现拥塞控制:
- 慢开始 (slow-start) ;
- 拥塞避免 (congestion avoidance);
- 快速重传 (fast retransmit);
- 快速恢复 (fast recovery)。
发送方维持一个叫做拥塞窗口cwnd(congestion window)的状态变量。当cwndssthresh时,改用拥塞避免算法。
- 慢开始:不要一开始就发送大量的数据,由小到大逐渐增加拥塞窗口的大小。拥塞窗口的增长每次都是收到确认报文段数量的2倍,当拥塞窗口到达了慢启动门限,就进入到拥塞避免阶段。
- 拥塞避免:不再以指数形式增长拥塞窗口,而是每经过一个往返时间RTT(Round-Trip Time)就将发送方的拥塞窗口+1,按照线性方式增长,如果发生网络拥塞,比如丢包时,就将慢启动门限设为原来的一半,然后将拥塞窗口设置为1,开始执行慢启动算法。
- 快速重传 (fast retransmit):快速重传要求接收方不要等待自己发送数据时才进行捎带确认,而是要立即发送确认,即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认。
- 快速重传规定,发送方只要一连接收到3个 重复确认,就知道接收方确实没有收到该报文段,因而应当立即进行重传,这样就不会出现超时,发送方也就不会误认为出现了网络拥塞。使用快速重传可以使整个网络的吞吐量提高约20%。快速重传后进入快速恢复。
- 快速恢复 (fast recovery):将慢启动门限值设置为原来的一半,然后将拥塞窗口设置为现在的慢启动的门限值,不再执行慢启动而是直接进入拥塞避免阶段 。使发送窗口成线性方式增长。
注:在拥塞避免阶段,拥塞窗口是按照线性规律增大的,这常称为 加法增大AI
。而一旦出现超时或3个确认重复,就要把门限值设置为当前拥塞窗口值得一半,并大大减小拥塞窗口的数值。这称为“乘法减小”MD,二者合并就是AIMD算法
TCP为什么比UDP慢?
-
第一步,TCP需要建立连接才能传输。一方发送,另一方传输,整个连接通畅才可以进行数据传输。
-
第二步,TCP会根据对方缓存大小进行数据分段和流量控制。当连接建立完成以后,双方先要进行沟通,了解清楚对方缓存区的大小,然后根据对方缓存区的大小对数据包进行切片,也就是所谓的TCP窗口。TCP的窗口大小在传输过程中会持续协商,必要的时候进行更改。
-
第三步,TCP会有端到端的校验和,并且存在出错重传机制。当传输过程的协商完成以后,开始正式传输对话内容。在此过程当中,TCP协议会进行端到端的校验和,如果传输过程中,传输的内容发生变化,接收方会发现校验失败,而发送方会触发出错重传机制。
-
第四步,TCP收到准确数据后发送确认,存在超时重传机制 。当接收方准确无误的收到内容以后,接收方会发出确认信息,如果发送方一段时间没有收到确认信息,会触发超时重传机制,并将需要传输的内容进行重传。
正是由于TCP拥有了如此之多的确认机制,才能确保待传输的内容准确无误的在端到端之间传输;也正是因为TCP如此严谨,大家才会产生TCP传输速度较慢的错觉。
TCP的确认应答机制是异步的吗?TODO
什么是粘包?粘包是怎么产生的?什么时候需要处理粘包现象?怎么解决粘包?(重要)
什么是粘包?
TCP粘包就是指发送方发送的若干包数据到达接收方时粘成了一个包,从接收缓冲区来看,后一包数据的头紧接着前一包数据的尾,出现粘包的原因是多方面的,可能是来自发送方,也可能是来自接收方。
造成TCP粘包的原因是什么?
-
发送方原因:TCP默认使用Nagle算法(主要作用:减少网络中报文段的数量,提高网络的利用率,来优化网络),而Nagle算法主要做两件事:
- 只有上一个分组得到确认,才会发送下一个分组
- 收集多个小分组,在一个确认到来时一起发送
- Nagle算法造成了发送方可能会出现粘包问题
-
接收方原因
- TCP接收到数据包时,并不会马上交到应用层进行处理,或者说应用层并不会立即处理。实际上,TCP将接收到的数据包保存在接收缓存里,然后应用程序主动从缓存读取收到的分组。这样一来,如果TCP接收数据包到缓存的速度大于应用程序从缓存中读取数据包的速度,多个包就会被缓存,应用程序就有可能读取到多个首尾相接粘到一起的包。
什么时候需要处理粘包现象?
- 如果发送方发送的多组数据本来就是同一块数据的不同部分,比如说一个文件被分成多个部分发送,这时当然不需要处理粘包现象
- 如果多个分组毫不相干,甚至是并列关系,那么这个时候就一定要处理粘包现象了
怎么解决粘包?
- 发送方:对于发送方造成的粘包问题,可以通过关闭Nagle算法来解决,使用TCP_NODELAY选项来关闭算法。
- 接收方:接收方没有办法来处理粘包现象,只能将问题交给应用层来处理。
- 应用层:应用层的解决办法简单可行,不仅能解决接收方的粘包问题,还可以解决发送方的粘包问题。
- 解决办法:循环处理,应用程序从接收缓存中读取分组时,读完一条数据,就应该循环读取下一条数据,直到所有数据都被处理完成,但是如何判断每条数据的长度呢?
- 格式化数据:每条数据有固定的格式(开始符,结束符),这种方法简单易行,但是选择开始符和结束符时一定要确保每条数据的内部不包含开始符和结束符。
- 发送长度:发送每条数据时,将数据的长度一并发送,例如规定数据的前4位是数据的长度,应用层在处理时可以根据长度来判断每个分组的开始和结束位置。
- 解决办法:循环处理,应用程序从接收缓存中读取分组时,读完一条数据,就应该循环读取下一条数据,直到所有数据都被处理完成,但是如何判断每条数据的长度呢?
UDP会不会产生粘包问题呢?不会
-
TCP为了保证可靠传输并减少额外的开销(每次发包都要验证),采用了基于流的传输,基于流的传输不认为消息是一条一条的,是无保护消息边界的(保护消息边界:指传输协议把数据当做一条独立的消息在网上传输,接收端一次只能接受一条独立的消息)。
-
UDP则是面向消息传输的,是有保护消息边界的,接收方一次只接受一条独立的信息,所以不存在粘包问题。
ARQ协议 TODO
网上有一句话:HTTP是长连接,TCP是短连接,说说你的理解?TODO
参考:https://blog.csdn.net/ls5718/article/details/51757467
3 三次握手 & 四次挥手
重要字段(状态码)
-
序号(sequence number):seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。
-
确认号(acknowledgement number):ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,ack=seq+1。
-
标志位(Flags):共6个,即URG、ACK、PSH、RST、SYN、FIN等。具体含义如下:
- URG:紧急指针(urgent pointer)有效。
- ACK:确认序号有效。(区分确认号ack)
- PSH:接收方应该尽快将这个报文交给应用层。
- RST:重置连接。
- SYN:发起一个新连接。
- FIN:释放一个连接。
那么这些字段有什么作用呢?
seq序号、ack序号:用于确认数据是否准确,是否正常通信。
标志位:用于确认/更改连接状态。
三次握手
简述 TCP 三次握手过程
- 第一次握手:客户端请求建立连接,向服务端发送一个
同步报文(SYN=1)
,同时选择一个随机数 seq = x 作为初始序列号,并进入SYN_SENT
状态,等待服务器确认。 - 第二次握手:服务端收到连接请求报文后,如果同意建立连接,则向客户端发送
同步确认报文(SYN=1,ACK=1)
,确认号为 ack = x + 1,同时选择一个随机数 seq = y 作为初始序列号,此时服务器进入SYN_RECV
状态。 - 第三次握手:客户端收到服务端的确认后,向服务端发送一个
确认报文(ACK=1)
,确认号为 ack= y + 1,序列号为 seq = x + 1
,客户端和服务器进入ESTABLISHED
状态,完成三次握手。
理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。
为什么需要三次握手,而不是两次?
- 防止已过期的连接请求报文突然又传送到服务器,从而产生错误和资源浪费。
- 客户端发送 A 报文段请求建立连接,由于网络延时未到达服务器
- 客户端在长时间得不到应答的情况下重新发送请求报文段 B,这次 B 顺利到达服务器,服务器随和客户端在分别收到对方确认报文后进入 ESTABLISHED 状态,双方建立连接并传输数据,之后正常断开连接。
- 此时姗姗来迟的 A 报文段才到达服务器,服务器随即返回确认报文并进入 ESTABLISHED 状态,但是已经进入 CLOSED 状态的客户端无法再接受确认报文段,更无法进入 ESTABLISHED 状态,这将导致服务器长时间单方面等待,造成资源浪费。
- 三次握手才能让双方均确认自己和对方的发送和接收能力都正常。
- 第一次握手:客户端只是发送处请求报文段,什么都无法确认,而服务器可以确认自己的接收能力和对方的发送能力正常;
- 第二次握手:客户端可以确认自己发送能力和接收能力正常,对方发送能力和接收能力正常;
- 第三次握手:服务器可以确认自己发送能力和接收能力正常,对方发送能力和接收能力正常;
- 三次握手才能告知对方自己的初始序号值,并确认收到对方的初始序号值。
- TCP 实现了可靠的数据传输,原因之一就是 TCP 报文段中维护了序号字段和确认序号字段,通过这两个字段双方都可以知道在自己发出的数据中,哪些是已经被对方确认接收的。
- 这两个字段的值会在初始序号值得基础递增,如果是两次握手,只有发起方的初始序号可以得到确认,而另一方的初始序号则得不到确认。
为什么要三次握手,而不是四次?
因为三次握手已经可以确认
- 双方的收发能力正常;
- 双方都知道彼此已经准备好,而且也可以完成对双方初始序号值得确认 。
什么是 SYN洪泛攻击?如何防范?
SYN洪泛攻击属于 DOS 攻击的一种,它利用 TCP 协议缺陷,通过发送大量的半连接请求,耗费 CPU 和内存资源。
原理:
- 在三次握手过程中,服务器发送 [SYN/ACK] 包(第二个包)之后、收到客户端的 [ACK] 包(第三个包)之前的 TCP 连接称为半连接(half-open connect),此时服务器处于 SYN_RECV (等待客户端响应)状态。如果接收到客户端的 [ACK] ,则 TCP 连接成功,如果未接受到,则会不断重发请求直至成功。
- SYN 攻击的攻击者在短时间内 伪造大量不存在的 IP 地址,向服务器不断地发送 [SYN] 包,服务器回复 [SYN/ACK] 包,并等待客户的确认。 由于源地址是不存在的,服务器需要不断的重发直至超时。
- 这些伪造的 [SYN] 包将长时间占用未连接队列,影响了正常的 SYN,导致目标系统运行缓慢、网络堵塞甚至系统瘫痪。
检测:当在服务器上看到大量的半连接状态时,特别是源 IP 地址是随机的,基本上可以断定这是一次SYN 攻击。
防范:
- 通过防火墙、路由器等过滤网关防护。
- 通过加固 TCP/IP 协议栈防范,如增加最大半连接数,缩短超时时间。
- SYN cookies技术。SYN Cookies 是对 TCP 服务器端的三次握手做一些修改,专门用来防范 SYN洪泛攻击的一种手段
三次握手连接阶段,最后一次ACK包丢失,会发生什么?(超时重传机制)
服务端:
- 根据 TCP的 超时重传机制,会等待3秒、6秒、12秒后重新发送SYN+ACK包,以便客户端重新发送ACK包。
- 如果重发指定次数之后,仍然未收到 客户端的ACK应答,那么一段时间后,服务端自动关闭这个连接。
客户端:
- 客户端认为这个连接已经建立,如果客户端向服务端发送数据,服务端将以RST包(Reset,标示复位,用于异常的关闭连接)响应。此时,客户端知道第三次握手失败。
四次挥手
简述 TCP 四次挥手过程
- 第一次挥手:客户端向服务端发送 连接释放报文(FIN=1) ,主动关闭连接,同时等待服务端的确认。
- 序列号 seq = m,即客户端上次发送的报文的最后一个字节的序号 + 1
- 第二次挥手:服务端收到连接释放报文后,立即发出 确认报文(ACK=1),序列号 seq = k,确认号 ack = m + 1。
- 这时 TCP 连接处于半关闭状态,即客户端到服务端的连接已经释放了,但是服务端到客户端的连接还未释放。这表示客户端已经没有数据发送了,但是服务端可能还要给客户端发送数据。
- 第三次挥手:服务端向客户端发送 连接释放报文(FIN=1,ACK=1) ,主动关闭连接,同时等待 A的确认。
- 序列号 seq = p,即服务端上次发送的报文的最后一个字节的序号 + 1。
- 确认号 ack = m + 1,与第二次挥手相同,因为这段时间客户端没有发送数据。
- 第四次挥手:客户端收到服务端的连接释放报文后,立即发出确认报文(ACK=1),序列号 seq = m + 1,确认号为 ack = p + 1。
- 此时,客户端就进入了 TIME-WAIT 状态。注意此时客户端到 TCP 连接还没有释放,必须经过 2*MSL(最长报文段寿命)的时间后,才进入 CLOSED 状态。而服务端只要收到客户端发出的确认,就立即进入 CLOSED 状态。可以看到,服务端结束 TCP 连接的时间要比客户端早一些。
- CLOSE_WAIT状态
为什么连接的时候是三次握手,关闭的时候却是四次握手?
服务器在收到客户端的 FIN 报文段后,可能还有一些数据要传输,所以不能马上关闭连接,但是会做出应答,返回 ACK 报文段。
服务器的ACK和FIN一般都会分开发送,从而导致多了一次,因此一共需要四次挥手。
为什么客户端的 TIME-WAIT 状态必须等待 2MSL ?
- 确保 ACK 报文能够到达服务端,从而使服务端正常关闭连接。
- 第四次挥手时,客户端第四次挥手的 ACK 报文不一定会到达服务端。服务端会超时重传FIN/ACK报文,此时如果客户端已经断开了连接,那么就无法响应服务端的二次请求,这样服务端迟迟收不到 FIN/ACK 报文的确认,就无法正常断开连接。
- MSL 是报文段在网络上存活的最长时间。客户端等待 2MSL 时间,即「客户端 ACK 报文 1MSL 超时 + 服务端 FIN 报文 1MSL 传输」,就能够收到服务端重传的 FIN/ACK 报文,然后客户端重传一次 ACK 报文,并重新启动 2MSL 计时器。如此保证服务端能够正常关闭。
- 如果服务端重发的 FIN 没有成功地在 2MSL 时间里传给客户端,服务端则会继续超时重试直到断开连接。
- 防止已失效的连接请求报文段出现在之后的连接中。
- TCP 要求在 2MSL 内不使用相同的序列号。客户端在发送完最后一个 ACK 报文段后,再经过时间2MSL,就可以保证本连接持续的时间内产生的所有报文段都从网络中消失。这样就可以使下一个连接中不会出现这种旧的连接请求报文段。或者即使收到这些过时的报文,也可以不处理它。
如果已经建立了连接,但是客户端出现故障了怎么办?(重要)
或者说,如果三次握手阶段、四次挥手阶段的包丢失了怎么办?如“服务端重发 FIN丢失”的问题。
简而言之,通过 定时器 + 超时重试机制,尝试获取确认,直到最后会自动断开连接。
具体而言,TCP 设有一个保活计时器。服务器每收到一次客户端的数据,都会重新复位这个计时器,时间通常是设置为 2 小时。若 2 小时还没有收到客户端的任何数据,服务器就开始重试:每隔 75 分钟发送一个探测报文段,若一连发送10 个探测报文后客户端依然没有回应,那么服务器就认为连接已经断开了。
TIME-WAIT 状态过多会产生什么后果?怎样处理?
从服务器来讲,短时间内关闭了大量的Client连接,就会造成服务器上 出现大量的TIME_WAIT连接 ,严重消耗服务器的资源,此时部分客户端就会显示连接不上。
从客户端来讲,会导致端口资源被占用,因为端口就65536个,被占满就会导致无法创建新的连接。
解决办法:
- 服务器 可以设置
SO_REUSEADDR 套接字
:即使此端口正忙(处于TIME_WAIT状态),也请继续并重用它。
- 调整系统内核参数,修改/etc/sysctl.conf文件,即修改
net.ipv4.tcp_tw_reuse
和tcp_timestamps
- net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连
接,默认为0,表示关闭; - net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
- net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连
- 强制关闭,发送 RST 包越过TIME_WAIT状态,直接进入CLOSED状态。
TIME_WAIT 是服务器端的状态?还是客户端的状态?
TIME_WAIT 是主动断开连接的一方会进入的状态
一般情况下,都是客户端所处的状态;服务器端一般设置不主动关闭连接。因为TIME_WAIT会太多,这也会消耗很多系统资源。
4 HTTP协议
HTTP协议的特点?
- HTTP允许传输任意类型的数据。传输的类型由Content-Type加以标记。
- 无状态。对于客户端每次发送的请求,服务器都认为是一个新的请求,上一次会话和下一次会话之间没有联系。
- 支持客户端/服务器模式。
HTTP报文格式(分为HTTP请求和HTTP响应)?
HTTP请求由请求行、请求头部、空行和请求体四个部分组成。
- 请求行:包括请求方法,访问的资源URL,使用的HTTP版本。GET和POST是最常见的HTTP方法,除此以外还包括DELETE、HEAD、OPTIONS、PUT、TRACE。
- 请求头:格式为属性名:属性值,服务端根据请求头获取客户端的信息,主要有cookie、host、connection、accept-language、accept-encoding、user-agent。
- 请求体:用户的请求数据如用户名,密码等。
请求报文示例:
POST /xxx HTTP/1.1 请求行
Accept:image/gif.image/jpeg, 请求头部
Accept-Language:zh-cn
Connection:Keep-Alive
Host:localhost
User-Agent:Mozila/4.0(compatible;MSIE5.01;Window NT5.0)
Accept-Encoding:gzip,deflate
username=dabin 请求体
HTTP响应也由四个部分组成,分别是:状态行、响应头、空行和响应体。
- 状态行:协议版本,状态码及状态描述 。
- 响应头:响应头字段主要有connection、content-type、content-encoding、content-length、set-cookie、Last-Modified,、Cache-Control、Expires。
- 响应体:服务器返回给客户端的内容。
HTTP1.0和HTTP1.1的区别?
- 长连接
- HTTP1.0默认使用短连接,每次请求都需要建立新的TCP连接,连接不能复用。
- HTTP1.1支持长连接,复用TCP连接,允许客户端通过同一连接发送多个请求。会有队头阻塞问题。
- 断点续传:HTTP1.0 不支持断点续传。HTTP1.1 新增了range字段,用来指定数据字节位置。
- 错误通知的管理 :在HTTP1.1中新增了24个错误状态响应码
- Host头处理 :在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名。到了HTTP1.1时代,虚拟主机技术发展迅速,在一台物理服务器上可以存在多个虚拟主机,并且它们共享一个IP地址,故HTTP1.1增加了HOST信息。
解释一下HTTP长连接和短连接?
- 在
HTTP/1.0
中,默认使用的是短连接
。也就是说,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。 - 但从
HTTP/1.1
起,默认使用长连接
,用以保持连接特性。使用长连接的HTTP协议,会在响应头
有加入这行代码:Connection:keep-alive
HTTP和TCP的区别?
- HTTP协议是应用层的协议,它是建立在TCP协议之上的一种应用。
- HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。
- 在HTTP 1.0中,客户端的每次请求都要求建立一次单独的连接,在处理完本次请求后,就自动释放连接。
- 在HTTP 1.1中则可以在一次连接中处理多个请求,并且多个请求可以重叠进行,不需要等待一个请求结束后再发送下一个请求。
HTTP 长连接什么时候断开?重要
-
最好使用支持HTTP/1.1的服务器,HTTP/1.1默认支持keep-alive,不需要像HTTP/1.0那样检测
Connection: keep-alive
。 -
浏览器的刷新也会断开长连接,如果在服务端有一些判断,要注意发生重复的可能。
-
在用户关闭浏览器的标签的时候,如果有多个页面和服务器保持长连接,服务器应检测对应的页面,并做清理。
-
将长连接服务器位于反向代理之后,应在反向代理服务器上设置保持keep-alive,如nginx。
-
检测用户刷新页面,如果刷新应询问用户是否真的刷新。这样可以减少一些误判断。
-
如因为业务需要将长连接和会话绑定(很多WEB IM都这样做),应注意清理服务端保持的长连接。
HTTP1.1和 HTTP2.0的区别?
HTTP2.0相比HTTP1.1支持的特性:
- 新的二进制格式:HTTP1.1 基于文本格式传输数据;HTTP2.0采用二进制格式传输数据,解析更高效。
- 多路复用 :在一个连接里,允许同时发送多个请求或响应,并且这些请求或响应能够 并行的传输而不被阻塞, 避免 HTTP1.1 出现的”队头堵塞”问题。
- 头部压缩 :
- HTTP1.1的头部(header)带有大量信息,而且每次都要重复发送;
- HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。
- 服务端推送:HTTP2.0允许服务器向客户端推送资源,无需客户端发送请求到服务器获取。
HTTP常见的状态码有哪些?
状态码开头代表类型:
- 200:服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
- 301 : (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD请求的响应)时,会自动将请求者转到新位置。
- 302:(临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
- 400 :客户端请求有语法错误,不能被服务器所理解。
- 403 :服务器收到请求,但是拒绝提供服务。
- 404 :(未找到) 服务器找不到请求的网页。
- 500: (服务器内部错误) 服务器遇到错误,无法完成请求。
- 实际中遇到的
- 上传视频的时候,Nginx有上传文件大小限制,如果超过Nginx大小,出现413
413:请求体过大
- 使用Nginx配置客户端大小
HTTP 与 HTTPS的区别?
- HTTP是超文本传输协议的,信息是明文传输,运行在TCP协议之上,端口是80。
- HTTPS是具有安全性的SSL加密传输协议,运行在SSL协议之上,SSL运行在TCP协议之上 ,端口是443,需要到CA机构申请证书,一般需要一定的费用。
讲一讲HTTPS的原理?
- 客户端请求 HTTPS 网址,然后连接到 server 的 443 端口(HTTPS 默认端口)。
- 采用 HTTPS 协议的服务器必须要有一套数字CA (Certification Authority)证书。颁发证书的同时会产生一个私钥和公钥。
- 私钥由服务端保存,不可泄漏。
- 公钥则是附带在证书的信息中,可以公开。
- 证书本身也附带一个证书电子签名,这个签名用来验证证书的完整性和真实性,可以防止证书被篡改。
- 服务器响应客户端请求,将证书传递给客户端,证书包含公钥和大量其他信息,比如证书颁发机构信息,公司信息和证书有效期等。
- 客户端解析证书并对其进行验证。如果证书不是可信机构颁布,或者证书中的域名与实际域名不一致,或者证书已经过期,就会向访问者显示一个警告,由其选择是否还要继续通信。
- 如果证书没有问题,客户端就会从服务器证书中取出服务器的公钥。然后客户端还会生成一个随机码KEY,并使用公钥将其加密。
- 客户端把加密后的随机码 KEY 发送给服务器,作为后面对称加密的密钥。
- 服务器在收到随机码 KEY 之后会使用私钥将其解密 。经过以上这些步骤,客户端和服务器终于建立了安全连接,完美解决了对称加密的密钥泄露问题,接下来就可以用对称加密愉快地进行通信了。
- 服务器使用密钥(随机码 KEY)对数据进行对称加密并发送给客户端,客户端使用相同的密钥 (随机码 KEY)解密数据。
- 双方使用对称加密愉快地传输所有数据。
GET请求和POST请求的区别?
使用上的区别
- GET使用URL或Cookie传参,而POST将数据放在BODY中,这个是因为HTTP协议用法的约定。
- GET方式提交的数据有长度限制,则POST的数据则可以非常大,这个是因为它们使用的操作系统和浏览器设置的不同引起的区别。
- POST比GET安全,因为数据在地址栏上不可见,这个说法没毛病,但依然不是GET和POST本身的区别。
本质区别
- GET和POST最大的区别主要是GET请求是幂等性的,POST请求不是。这个是它们本质区别。
- 幂等性是指一次和多次请求某一个资源应该具有同样的副作用。简单来说意味着对同一URL的多个请求应该返回同样的结果。
什么是 Cookie 和 Session ?
什么是 Cookie
- HTTP Cookie(也叫 Web Cookie或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据
- Cookie会在浏览器下次向同一服务器发起HTTP请求时被携带并发送到服务器上。
- Cookie通常用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。
什么是 Session
- Session 代表着服务器和客户端一次会话的过程。
- Session 对象存储特定用户会话所需的属性及配置信息。
- 这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。
- 当客户端关闭会话或者Session 超时失效时会话结束。
Cookie和Session的区别?
- 作用范围不同,Cookie 保存在客户端,Session 保存在服务器端。
- 有效期不同,Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭或者 Session 超时都会失效。
- 隐私策略不同,Cookie 存储在客户端,容易被窃取;Session 存储在服务端,安全性相对 Cookie 要好一些。
- 存储大小不同, 单个 Cookie 保存的数据不能超过 4K;对于 Session 来说存储没有上限,但出于对服务器的性能考虑,Session 内不要存放过多的数据,并且需要设置 Session 删除机制。
Cookie 和 Session 是如何配合的呢?(SessionID)
-
用户第一次请求服务器的时候
- 服务器根据用户提交的相关信息,创建对应的 Session ,请求返回时将此 Session 的唯一标识信息 SessionID 返回给浏览器;
- 浏览器接收到服务器返回的 SessionID 信息后,会将此信息存入到 Cookie 中,同时 Cookie 记录此 SessionID 属于哪个域名。
-
当用户第二次访问服务器的时候
- 请求会阿自动判断此域名下是否存在 Cookie 信息**,如果存在自动将Cookie 信息也发送给服务端;
- 服务器端会从 Cookie 中获取 SessionID,再根据 SessionID 查找对应的Session 信息;
- 如果没有找到说明用户没有登录或者登录失效;
- 如果找到 Session 证明用户已经登录可执行后面操作。
根据以上流程可知,SessionID 是连接 Cookie 和 Session 的一道桥梁,大部分系统也是根据此原理来验证用户登录状态。
5 Linux
什么是用户态和内核态?
用户态和内核态是操作系统的两种运行状态。
- 内核态:处于内核态的 CPU 可以访问任意的数据,包括外围设备,比如网卡、硬盘等,处于内核态的 CPU 可以从一个程序切换到另外一个程序,并且占用 CPU 不会发生抢占情况,一般处于特权级 0 的状态我们称之为内核态。
- 用户态:处于用户态的 CPU 只能受限的访问内存,并且不允许访问外围设备,用户态下的 CPU 不允许独占,也就是说 CPU 能够被其他程序获取。
那么为什么要有用户态和内核态呢?
这个主要是访问能力的限制的考量,计算机中有一些比较危险的操作,比如设置时钟、内存清理,这些都需要在内核态下完成,如果随意进行这些操作,那你的系统得崩溃多少次。
用户态和内核态是如何切换的?TODO
Linux常用命令
查看端口占用情况
- 查看已知端口占用情况
netstat -anp | grep 8080 # 或者 netstat -tln | grep 8080
- 查看全部端口占用情况
netstat -anp # 或者 netstat -tln
- 查看具体端口被哪个程序占用、
lsof -i :8080
linux切割日志的方式
-
head:获取文本文件的开始 n 行。
head -50000 java.log > blog.log
-
让tail:来获取文本最后行。
tail -50000 java.log > blog.log
-
sed:从第 N 行截取到第M行。( N > 0 , M < FileLineNumber )
sed -n '1,50000p' java.log > blog.log
-
split 命令分割大 log 文件
-
每 3000 行切分生成一个心文件,–verbose 显示切分进度
split -l 3000 java.txt blog.log --verbose
-
每 100M 切分成一个新的文件,–verbose 显示切分进度
split -d 100m java.txt blog.log --verbose
-
linux打印日志的方式
- tail
# 实时监控日志尾部500行日志。日志有追加时,会实时打印,不会中断,除非ctrl+c 中断 tail -500f app.log # 查询日志尾部最后500行的日志 tail -n 500 app.log # 输出文件末尾包含关键字的行,当文件有追加时,会输出后续添加的行,不会中断输出,除非ctrl+c中断 tail -f file.log | grep "关键字" # 输出文件的后100行中包含关键字的行和该行的前后10行 tail -n 100 file.log | grep "关键字" -B10 -A10
- grep:
grep “关键字” logname
6 操作系统
进程和线程的区别?
- 调度:
进程是资源管理的基本单位
,线程是程序执行的基本单位
。 - 切换:线程上下文切换比进程上下文切换要快得多。
- 拥有资源: 进程是拥有资源的一个独立单位,线程不拥有系统资源,但是可以访问隶属于进程的资源。
- 系统开销: 创建或撤销进程时,系统都要为之分配或回收系统资源,如内存空间,I/O设备等,OS所付出的开销显著大于在创建或撤销线程时的开销,进程切换的开销也远大于线程切换的开销。
什么是协程?
线程数量多时会产生的问题:
- 一是系统线程会占用非常多的内存空间;
- 二是过多的线程切换会占用大量的系统时间。
协程刚好可以解决上述2个问题。协程运行在线程之上,当一个协程执行完成后,可以选择主动让出,让另一个协程运行在当前线程之上。协程并没有增加线程数量,只是在线程的基础之上通过分时复用的方式运行多个协程,而且协程的切换在用户态完成,切换的代价比线程从用户态到内核态的代价小很多
。
进程间通信方式有哪些?
- 管道:管道这种通讯方式有两种限制,一是半双工的通信,数据只能单向流动,二是只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。管道可以分为两类:匿名管道和命名管道。
- 匿名管道是单向的,只能在有亲缘关系的进程间通信;
- 命名管道以磁盘文件的方式存在,可以实现本机任意两个进程通信。
- 信号 : 信号是一种比较复杂的通信方式,信号可以在任何时候发给某一进程,而无需知道该进程的状态。
为什么虚拟地址空间切换会比较耗时?
进程都有自己的虚拟地址空间,把虚拟地址转换为物理地址需要查找页表,页表查找是一个很慢的过程,因此通常使用Cache来缓存常用的地址映射,这样可以加速页表查找,这个Cache就是TLB(translation Lookaside Buffer,TLB本质上就是一个Cache,是用来加速页表查找的)。
由于每个进程都有自己的虚拟地址空间,那么显然每个进程都有自己的页表,那么当进程切换后页表也要进行切换,页表切换后TLB就失效了,Cache失效导致命中率降低,那么虚拟地址转换为物理地址就会变慢,表现出来的就是程序运行会变慢,而线程切换则不会导致TLB失效,因为线程无需切换地址空间,因此我们通常说线程切换要比较进程切换块,原因就在这里。