计算机网络面试总结
OSI开放互联参考模型
物理层:满足两台机器通信需求,发送比特流(集线器),单位是比特流
数据链路层:如何格式化数据已进行传输,控制物理介质的访问,提供错误检测,确保数据传输的可靠性(流控制)设备是交换机,单位是帧
网络层:网络地址翻译成物理地址,并考虑发送方路由到接受方(路由器)单位是数据包
传输层:建立连接,对数据包分割,保证次序(进程,端口)单位是数据段
会话层:建立和管理应用程序的发送数据包和寻址
表示层:不同系统的语法语义翻译,格式化数据
应用层:为操作系统或者网络应用程序提供网络访问的接口
OSI是模型,TCP/IP是这个模型的实现。
TCP/IP协议
传输控制协议TCP简介:
- 面向连接的、可靠的、基本字节流的传输层通信协议
- 将应用层的数据流分割成报文段并发发送给目标节点的TCP层
- 数据包都有序号,对方接收到则发送ACK确认,未收到则重传
- 使用校验和来校验数据在传输过程中是否有误
提示:两进程通信的方法:管道、内存共享、信号量、消息队列。两进程通信需要知道唯一标识这一进程。本地唯一:pid
多主机可以使用套接字:
IP地址 + 协议(TCP) + 端口号 可以 标识一个进程
报文头
原端口和目的端口:就字面意思,注意:TCP报头中的源端口号和目的端口号同IP数据报中的源IP与目的IP唯一确定一条TCP连接。
序列号和确认号:序号是本报文段发送的数据组的第一个字节的序号。在TCP传送的流中,每一个字节(注意单位)一个序号。e.g.一个报文段的序号为300,此报文段数据部分共有100字节,则下一个报文段的序号为400。所以序号确保了TCP传输的有序性。
确认号,即ACK,指明下一个期待收到的字节序号,表明该序号之前的所有数据已经正确无误的收到。确认号只有当ACK标志为1时才有效。比如建立连接时,SYN报文的ACK标志位为0。
数据偏移:由于首部可能含有可选项内容,因此TCP报头的长度是不确定的,用来指示了数据区在报文段中的起始偏移值。
保留
控制位(TCP Flags)
URG:紧急指针标志 ACK:确认序号标志 PSH:push标志(尽快交付)
RST:重制连接标志(崩溃,拒绝非法) SYN:同步序号,用于建立连接过程
FIN:finish标注,用于释放连接
窗口:滑动窗口的大小,用来告知发送端接受端的缓存大小,以此控制发送端发送数据的速率,窗口大小时一个16bit字段,因而窗口大小最大为65535。
奇偶校验和:包括 TCP 头部和 TCP 数据,以 16 位字进行计算所得
紧急指针:只有当 URG 标志置 1 时紧急指针才有效。紧急指针是一个正的偏移量,和顺序号字段中的值相加表示紧急数据最后一个字节的序号。
选项和填充:最常见的可选字段是最长报文大小,又称为MSS(Maximum Segment Size),它表示本端所能接受的最大报文段的长度。
选项长度不一定是32位的整数倍,所以要加填充位,即在这个字段中加入额外的零,以保证TCP头是32的整数倍。
数据部分: TCP 报文段中的数据部分是可选的。在一个连接建立和一个连接终止时,双方交换的报文段仅有 TCP 首部。如果一方没有数据要发送,也使用没有任何数据的首部来确认收到的数据。在处理超时的许多情况中,也会发送不带任何数据的报文段。
三次握手流程
握手是为了建立连接(是全双工的),TCP三次握手的流程图如下:
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接:
- 第一次握手,建立连接时,客户端发送SYN包(seq=x)到服务器,并进入SYN_SEND状态,等待服务器确认。
- 第二次握手,服务器收到SYN包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(seq=y),即SYN+ACK包,此时服务器进入SYN_RECV状态。
- 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
为什么需要三次握手才能建立起连接?
- 为了初始化Sequence Number的初始值
- 通信双方要互相通知对方自己初始化的Sequence Number,这个序号要作为以后数据通信的序号,以保证应用层接收到的数据不会网络上的传输问题而乱序,即TCP会根据这个序号来拼接数据。
- 因此,在服务器回发它的Sequence Number(第二次握手)后,还需要客户端发送ACK报文给服务器(第三次握手)
首次握手的隐患--SYN超时(没收到第三次握手),使服务器有遭到SYN Flood的风险
SYN Flood:恶意程序给服务端发送大量syn信号,耗尽服务端syn队列,使服务端不能正常处理其他请求
问题起因分析:
Server收到Client的SYN,回复SYN-ACK的时候未收到ACK确认----即没收到第三次握手(客户端掉线了,第三次的确认没发)
Server不断重试(5次 分别等待1 2 4 8 16 32秒)直到超时,Linux默认等待63秒才断开连接
针对SYN Flood的防护措施:
SYN队列满后,通过tcp_syncookies参数回发SYN Cookie
若为正常连接则Client会回发SYN Cookie,直接建立连接
如果建立连接后,Client出现故障怎么办?
保活机制:在保活时间内(keep alive time)
- 向对方发送保活探测报文,如果未收到响应则根据(保活时间间隔)继续发送
- 尝试次数达到保活探测数仍未收到响应则中断连接
四次挥手
seq=u: 客户端最后传送的一个字节的序号+1
挥手流程(客户端主动关闭)
挥手是为了终止连接,TCP四次挥手的流程如下:
TCP采用四次挥手来释放连接:
- 第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态;
- 第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态;
- 第三次握手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态;
- 第四次握手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。
为什么会有TIME_WAIT状态(等待2*MSL「最长报文段寿命时间」时间)
原因:
- 1.确保有足够的时间让对方收到ACK包(eg:如果服务端没收到ack,服务端会重发FIN包,这样正好是2msl)
- 2.避免新旧连接混淆(避免跟后边的其他连接混在一起,因为有些路由器会缓存IP数据包,服务端延迟收到的包,就有可能跟新连接的包混在一起)
为什么需要四次挥手才能断开连接
- 因为TCP是全双工的(可以是客户端提出结束,也可以是服务端),发送方和接收方都需要发送FIN包文和收到ACK报文
- 有一方是被动关闭的,所以看上去是四次挥手(FIN和ACK包分开发的)
服务器出现大量CLOSE_WAIT状态的原因
client关闭socket连接后,服务端方忙于读或写,没有及时关闭连接
- 检查代码,特别是释放资源的代码
- 检查配置,特别是处理请求的线程配置
过多的time wait造成的原因是高并发,短连接,可通过改变linux参数减少这种情况
查看linunx网络指令:
netstat -n | awk '/^tcp/{++S[$NF]}END{for(a in S) print a,S[a]]}'
UDP报文结构
UDP的特点:
- 面向非连接
- 不维护连接状态,支持同时向多个客户端传输相同的消息
- 数据包报头只有8个字节,额外开销极小
- 吞吐量只受限于数据生成速率,传输速率以及机器性能
- 尽最大努力交付,不保证可靠性交付,不需要维持复杂的链接状态表
- 面向报文,不对应用程序提交的报文信息进行拆分或者合并
TCP和UDP的区别
- 面向连接 vs 无连接
- 可靠性(TCP可靠[因为有确认、重传机制])
- 有序性(TCP有序[序列号机制])
- 速度(TCP速度慢、udp[所以适合在线视频、广播、多人在线游戏场景])
- 量级(TCP重量级、UDP轻量级)
TCP:可靠、数据有序、速度慢、重量级,举例:收发邮件、远程登录、web
UDP:不可靠、数据无序、速度快、轻量级,举例:在线视频、广播、多人在线游戏
TCP的滑动窗口
RTT和RTO介绍:
- RTT:发送一个数据包收到对应的ACK,所花费的时间(Round Trip Time:一个连接的往返时间)
- RTO:重传时间间隔(Retransmission Time out)
- 滑动窗口基于RTO
TCP使用滑动窗口解决了流量控制与乱序重排
- 保证TCP的可靠性(建立在确认重传机制上)
- 保证TCP的流量控制特性
TCP的滑动窗口
名词解释:
发送端
LastByteAcked:最后一个ACK(确认收到)的数据
LastByteWritten:上层应用最后一个写的数据,即当前程序准备好要发送的最新的一个数据(还没发送)
LastByteSent:最后一个已经发送的数据,还没收到ack
接收端
LastByteRead:读取到的并且已经处理的最后一条数据(已经回复ACK的)
NextByteExpected:已经收到的连续数据中最大的一条(还没回复ACK的)
LastByteRecvd:已收到的最后一条数据(不连续)
窗口数据的计算过程:
1.接收方计算AdvertisedWindow:
AdvertisedWindow:建议发送端发送的最大数据量
AdvertisedWindow = MaxRcvBuffer - (LastByteRecvd-LastByteRead)
MaxRcvBuffer接收端缓存池大小
2.将AdvertisedWindow发送到发送方,发送方根据AdvertisedWindow计算EffectiveWindow
EffectiveWindow:发送方窗口内,剩余可发送的最大数据量
EffectiveWindow = AdvertisedWindow - (LastByteSent-LastByteAcked)
滑动窗口的基本原理:(滑动窗口要比(接收、发送)缓存小)
- 1.发送方发送缓存中的数据状态分类:
- 2.滑动窗口:Category#2 + Category#3
- 3.当发送方收到接收方的数据ack时,窗口就会滑动。
4.接收方接收缓存的状态分类:
接收到并已确认的数据
未接收,并允许发送方发送的大小
未接收,并且不能接收的状态,已经达到了窗口阈值
- 5.接收窗口:Category#3
- 当接收方接收到连续数据后并发出ack信号后,窗口就会滑动
流量控制:
- 滑动窗口的大小可以依据一定策略动态调整,应用会根据自身处理能力的变化,通过本端TCP接收窗口的大小的控制,实现对端的发送窗口改变进行流量控制。
- 接收方通过计算得出AdvertisedWindow,并发送给发送方。
- 发送方:根据AdvertisedWindow计算可发送最大的数据量EffectiveWindow。
乱序控制:
接收方:按连续顺序确认接收并发送ack信号。
发送方:按连续顺序发送数据。
拥塞控制
拥塞控制与流量控制的区别
拥塞控制是防止过多的数据注入到网络中,可以使网络中的路由器或链路不致过载,是一个全局性的过程。
流量控制是点对点通信量的控制,是一个端到端的问题,主要就是抑制发送端发送数据的速率,以便接收端来得及接收。
一个小问题:阈值ssthresh的单位是什么? 答:报文段
慢开始:慢开始cwnd指数增长,TCP开始发送设置cwnd=1
当cnwd<ssthresh,使用慢开始算法
当cnwd=ssthresh,既可使用慢开始算法,也可以使用拥塞避免算法
当cnwd>ssthresh,使用拥塞避免算法
拥塞避免:让拥塞窗口cwnd缓慢地增大,即每经过一个往返时间RTT就把发送方的拥塞控制窗口加一
这两个阶段只要出现超时,把慢开始门限设置为出现拥塞时的发送窗口大小的一半。然后把拥塞窗口设置为1,执行慢开始算法。
快重传:要求接收方在收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)
发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。
快恢复:
1.采用快恢复算法时,慢开始只在TCP连接建立时和网络出现超时时才使用。
2.当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把ssthresh门限减半。但是接下去并不执行慢开始算法。
3.考虑到如果网络出现拥塞的话就不会收到好几个重复的确认,所以发送方现在认为网络可能没有出现拥塞。所以此时不执行慢开始算法,而是将cwnd设置为ssthresh的大小,然后执行拥塞避免算法。
这里注意区分超时和三个ack的区别
面试问题:tcp保证可靠性的原因?答:校验和+序列号与确认应答机制+超时重传+流量控制(滑动窗口)+拥塞控制都扯一下
HTTP相关
HTTP:超文本传输协议 ,应用册层协议
HTTP的主要特点:
- 1.支持客户/服务器模式
2.简单快速
客户端向服务器请求服务时,只需传输请求方法和路径,由于http协议简单,是的http服务器的程序规模小,因此通信速度很快
3.灵活
允许传输任意类型的数据对象,由content-type标记
4.无连接
限制每次连接只处理一个请求,服务器处理完请求并收到客户端确认后,即断开连接,这种方式节省传输时间。
在Http1.1,后默认采用长连接,即服务器需要等待一定时间后才断开连接,以保证连接特性
5.无状态
协议对于事物处理没有记忆能力,缺少状态意味着如果后续处理需要前面的信息,则需要重传,这样可能导致每次连接传送的数据量增大。
简单理解为,http服务起不会记住你的登录状态,你是谁,是由另外的机制(cookie\session)解决的。
HTTP请求结构:
例:
Request Header:
GET: /sample.Jsp HTTP/1.1 ** //请求行
Host: www.uuid.online //请求的目标域名和端口号
Origin: http://localhost:8081 //请求的来源域名和端口号 (跨域请求时,浏览器会自动带上这个头信息)
Referer: https:/localhost:8081/link?query=xxxxx //请求资源的完整URI
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36 //浏览器信息
Cookie: BAIDUID=FA89F036:FG=1; BD_HOME=1; sugstore=0 //当前域名下的Cookie
Accept: text/html,image/apng //代表客户端希望接受的数据类型是html或者是png图片类型
Accept-Encoding: gzip, deflate //代表客户端能支持gzip和deflate格式的压缩
**Accept-Language: **zh-CN,zh;q=0.9 //代表客户端可以支持语言zh-CN或者zh(值得一提的是q(0~1)是优先级权重的意思,不写默认为1,这里zh-CN是1,zh是0.9)
Connection: keep-alive //告诉服务器,客户端需要的tcp连接是一个长连接
HTTP响应结构:
Response Header:
HTTP/1.1 200 OK // 响应状态行
Date: Mon, 30 Jul 2018 02:50:55 GMT //服务端发送资源时的服务器时间
Expires: Wed, 31 Dec 1969 23:59:59 GMT //比较过时的一种验证缓存的方式,与浏览器(客户端)的时间比较,超过这个时间就不用缓存(不和服务器进行验证),适合版本比较稳定的网页
Cache-Control: no-cache // 现在最多使用的控制缓存的方式,会和服务器进行缓存验证,具体见博文”Cache-Control“
etag: "fb8ba2f80b1d324bb997cbe188f28187-ssl-df" // 一般是Nginx静态服务器发来的静态文件签名,浏览在没有“Disabled cache”情况下,接收到etag后,同一个url第二次请求就会自动带上“If-None-Match”
Last-Modified: Fri, 27 Jul 2018 11:04:55 GMT //是服务器发来的当前资源最后一次修改的时间,下次请求时,如果服务器上当前资源的修改时间大于这个时间,就返回新的资源内容
Content-Type: text/html; charset=utf-8 //如果返回是流式的数据,我们就必须告诉浏览器这个头,不然浏览器会下载这个页面,同时告诉浏览器是utf8编码,否则可能出现乱码
Content-Encoding: gzip //告诉客户端,应该采用gzip对资源进行解码
Connection: keep-alive //告诉客户端服务器的tcp连接也是一个长连接
http请求响应的步骤:
客户端连接到Web服务器(建立一个TCP套接字连接)
发送HTTP请求(通过TCP套接字发送)
服务器接受请求并返回HTTP响应(将响应数据写到TCP套接字)
释放连接TCP连接(
1.若连接模式为close,则服务起主动关闭TCP连接,客户端被动关闭TCP连接。
2.若连接模式为keep-alive,则该连接会保持一段时间,在该时间内,服务器可以继续接收请求)客户端浏览器解析HTML内容
(面试题)在浏览器地址栏键入RUL,按下回车后经历的流程:
- DNS解析,解析url中域名对应的IP地址,会依次浏览器缓存、系统缓存、路由器缓存、IPS服务器缓存、根域名服务器缓存、顶级域名缓存
- 2.TCP连接(三次握手)
- 3.发送HTTP请求
- 4.服务器处理请求并返回HTTP报文
- 5.浏览器解析渲染界面
- 6.连接结束(四次挥手)
(面试题)常见HTTP状态码:
- 五种可能的取值:
- 1XX:指示信息--表示请求以接收,继续处理
- 2XX:成功--表示请求已经被成功接收、理解、处理
- 3XX:重定向--要完成请求必须进行更进一步的操作
- 4XX:客户端错误--请求有语法错误或请求无法实现
- 5XX:服务端错误--服务器未能实现合法的请求
常见状态码:
- 200 OK :正常返回信息
- 400 Bad Rqquest:客户端请求有语法错误,不能被服务器理解
- 401 Unauthorized:请求未经授权,这个状态代码和WWW-Authenticate报头域一起使用
- 403 Forbidden:服务器收到请求,但是拒绝提供服务
- 404 Not Found:请求资源不存在,eg,输入了错误的URL
- 500 Internal Server Error:服务器发生了不可预期的错误
- 503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常
(面试题)GET请求和POST请求的区别:
1.Http报文层面:
GET请求信息放在URL,POST放在报文体中
GET请求中一般浏览器对url长度有限制;POST请求数据长度无限制
2.数据库层面:GET服务幂等性(对数据库的一次操作和多次操作上一致的)和安全性(没有改变数据库的数据),POST不符合
3.其他层面:GET可以被缓存,被存储,而POST不行
GET请求的内容会被保存在浏览器中
超过90%的GET请求都被CDN缓存了,大大减少web服务起的负担
Http的请求方法:
GET: 请求指定的页面信息,并返回实体主体。
HEAD: 类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头
POST: 向指定资源提交数据进行处理请求(例如提交表单或者上传文件),数据被包含在请求体中,POST 请求可能会导致新的资源的建立和/或已有资源的修改
PUT:从客户端向服务器传送的数据取代指定的文档的内容
DELETE:请求服务器删除指定的页面
CONNECT : HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器
OPTIONS: 允许客户端查看服务器的性能
TRACE :回显服务器收到的请求,主要用于测试或诊断
PATCH : PUT 方法的补充,用来对已知资源进行局部更新
Cookie简介
- 是由服务器发给客户端的特殊信息,以文本的形式存放在客户端
- 客户端再次请求的时候,会把Cookie回发(存放于响应头)
- 服务器接收到后,会解析Cookie生成与客户端相对应的内容
实例:登录功能中 请记住我,就是通过cookie实现的 - Cookie的设置以及发送过程:(4步)
session简介
服务器端的机制,在服务器上保存的信息
解析客户端请求并操作session id(客户端传过来的),按需保存状态信息
如果客户端请求中有session id,说明以为该客户创建session,就会在服务端检索用户信息。
如果客户端请求中无session id,则服务端为客户创建session,并生成session id
Session的实现的两种方式(JSESSIONID)
1.使用Cookie来实现
2.使用URL回写来实现
开发者模式中查看session:
(面试题)Cookie和Session的区别?(这种机制使http具备状态,eg:能记住登录信息)
- 1.Cookie数据存放在客户的浏览器上,Session数据存放在服务器上
- 2.Session相对Cookie更安全
- 3.若考虑减轻服务器负担,应当使用Cookie
(面试题)HTTP和HTTPS的区别
- HTTPS需要到CA申请证书(一般会收费),HTTP不需要
- HTTPS密文传输,HTTP明文传输
- 连接方式不同,HTTPS默认使用443端口,HTTP使用80端口
- HTTPS=HTTP+加密+认证+完整性保护,较HTTP安全
SSL(Security Sockets Layer,安全套阶层)
- 为网络通信提供安全及数据完整性的一种安全协议
- 是操作系统对外的API,SSL3.0后更名为TLS
- 采用身份验证和数据加密保证网络通信的安全和数据的安全性
加密的方式:
- 对称加密:加密和解密都是用同一个密钥(DES)
- 非对称加密:加密使用的密钥和解密使用的密钥是不相同的(公钥和私钥,RSA)
- 哈希算法:将任意长度的信息转换为固定长度的值,算法不可逆(MD5)
- 数字签名:证明某个消息或者文件是发出/认同的
HTTPS数据传输流程
- 浏览器将支持的加密算法信息发送给服务器
- 服务器选择一套浏览器支持的加密算法,以证书的形式回发浏览器
- 浏览器验证证书合法性,并结合证书公钥加密信息发送给服务器
- 服务器使用私钥解密信息,验证哈希,加密响应消息回发浏览器
- 浏览器解密响应消息,并对消息进行验真,之后进行加密交互数据
HTTPS未必真安全:
- 浏览器默认填充http://,请求需要进行跳转,有被劫持的风险
- 可以使用HSTS(HTTP Strict Transport Security)优化
Socket简介
Socket是对TCP/IP协议的抽象,是操作系统对外开放的接口(read write create listen等)
Socket通信流程:
面试题:
TCP:
UDP: