大纲
ISO/OSI模型
- 键入网址到网页显示,期间发生了什么?
- 解析URL,生成 HTTP 请求消息;(应用层)
- DNS 域名解析;(应用层)
- 将 HTTP 的传输工作交给操作系统的协议栈;(应用层)
- TCP 可靠传输;(传输层)
- IP 远程定位;(网络层)
- MAC 两点传输;(数据链路层ARP)
- 网卡,将数字信号转化为电信号;(物理层)
- 交换机转发包;
- 路由器,转发网络包到下一个路由器或目标设备;
- 服务器接收数据,响应数据包。
应用层
HTTP
- HTTP 常见的状态码,有哪些?
1xx:1xx类状态码属于提示信息,是协议处理中的一种中间状态,实际用到的比较少。2xx2xx类状态码表示服务器成功处理了客户端的请求,也是我们最愿意看到的状态。「200 OK」是最常见的成功状态码,表示一切正常。如果是非 HEAD 请求,服务器返回的响应头都会有 body数据。
「204 No Content」也是常见的成功状态码,与 200 OK 基本相同,但响应头没有 body 数据。
「206 Partial Content」是应用于HTTP 分块下载或断点续传,表示响应返回的 body 数据并不是资源的全部,而是其中的一部分,也是服务器处理成功的状态。
3xx 3xx类状态码表示客户端请求的资源发送了变动,需要客户端用新的 URL 重新发送请求获取资源,也就是重定向。
「301 Moved Permanently」表示永久重定向,说明请求的资源已经不存在了,需改用新的 URL 再次访问。\
「302 Found」表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问。\
301 和 302 都会在响应头里使用字段 Location ,指明后续要跳转的 URL,浏览器会自动重定向新的 URL。
「304Not Modified」不具有跳转的含义,表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,用于缓存控制。
4xx 4xx类状态码表示客户端发送的报文有误,服务器无法处理,也就是错误码的含义。
「400 Bad Request」表示客户端请求的报文有错误,但只是个笼统的错误。
「403 Forbidden」表示服务器禁止访问资源,并不是客户端的请求出错。
「404 Not Found」表示请求的资源在服务器上不存在或未找到,所以无法提供给客户端。
5xx 5xx 类状态码表示客户端请求报文正确,但是服务器处理时内部发生了错误,属于服务器端的错误码。
「500 Internal Server Error」与 400 类型,是个笼统通用的错误码,服务器发生了什么错误,我们并不知道。
「501 Not Implemented」表示客户端请求的功能还不支持,类似"即将开业,敬请期待"的意思。
「502 Bad Gateway」通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误。
「503 Service Unavailable」表示服务器当前很忙,暂时无法响应服务器,类似"网络服务正忙,请稍后重试"的意思。
- HTTP的常见字段有哪些?
- Host字段:客户端发送请求时,用来指定服务器的域名。
- Connection 字段:最常用于客户端要求服务器使用TCP持久连接,以便其他请求复用。
- HTTP/1.1 版本的默认连接都是持久连接,但为了兼容老版本的 HTTP,需要指定 Connection 首部字段的值为Keep-Alive 。 一个可以复用的 TCP 连接就建立了,直到客户端或服务器主动关闭连接。但是,这不是标准字段。
- Content-Length 字段 :服务器在返回数据时,会有 Content-Length 字段,表明本次回应的数据长度。
- Content-Type 字段:用于服务器回应时,告诉客户端,本次数据是什么格式。
- Content-Encoding 字段:说明数据的压缩方法。表示服务器返回的数据使用了什么压缩格式。
- GET和POST的区别?
- GET请求在URL中传送的参数是有长度限制的,而POST没有。
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
- GET参数通过URL传递,POST放在Request body中。
- GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- GET请求只能进行url编码,而POST支持多种编码方式。
- GET请求会被浏览器主动cache,而POST不会,除非手动设置。
- GET产生的URL地址可以被Bookmark,而POST不可以。
- GET在浏览器回退时是无害的,而POST会再次提交请求。
HTTPS
- SSL(https)的连接过程?
- 客户端提交https请求;
- 服务器响应客户,并把证书公钥发给客户端;
- 客户端验证证书公钥的有效性;
- 有效后,会生成一个会话密钥;
- 用证书公钥加密这个会话密钥后,发送给服务器;
- 服务器收到公钥加密的会话密钥后,用私钥解密,取出会话密钥;
- 客户端与服务器双方利用这个会话密钥加密要传输的数据进行通信。
传输层
TCP
- 说一下三次握手? 刚开始客户端处于 closed 的状态,服务端处于 listen 状态。然后:
- 第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列列号 ISN(c)。此时客户端处于SYN_Send 状态。
- 第二次握手:服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号 ISN(s),同时会把客户端的 ISN + 1 作为 ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于 SYN_REVD 的状态。
- 第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK的值,表示已经收到了服务端的 SYN 报文,此时客户端处于 establised 状态。
- 服务器器收到 ACK 报文之后,也处于 establised 状态,此时,双方以建立起了链接。
- 为什么TCP是三次握手?不是两次、四次?
TCP建立连接时,通过三次握手能防止历史连接的建立,能减少双方不必要的资源开销,能帮助双方同步初始化序列号。序列号能够保证数据包不重复、不丢弃和按序传输。
不使用「两次握手」和「四次握手」的原因 :
- 「两次握手」:无法防止历史连接的建立,会造成双方资源的浪费,也无法可靠的同步双方序列号;
- 「四次握手」:三次握手就已经理论上最少可靠连接建立,所以不需要使用更多的通信次数。
为什么不可以是两次握手?
当客户端向服务器端发送一个连接请求时,由于某种原因长时间驻留在网络节点中,无法到达服务器端,由于TCP的超时重传机制,当客户端在特定的时间内没有收到服务器端的的确认应答时,就会重新向服务器端发送连接请求,该请求到达服务器端并建立连接,进行数据传输,当数据传输完成时,释放了TCP连接。
- 说一下四次挥手? 刚开始双方都处于 establised 状态,假如是客户端先发起关闭请求,则:
- 第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于CLOSED_WAIT1状态。
- 第二次握手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列列号值 + 1 作为 ACK 报文的序列列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT2状态。
- 第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列列号。此时服务端处于 LAST_ACK 的状态。
- 第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列列号值 + 1 作为⾃己ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态。
- 服务端收到 ACK 报⽂文之后,就处于关闭连接了了,处于 CLOSED 状态。
超时重传
超时重传:重传机制的其中一个方式,就是在发送数据时,设定一个定时器,当超过指定的时间后,没有收到对方的ACK确定应答报文,就会重发该数据,也就是我们常说的超时重传。
TCP会在以下两种情况发生超时重传:数据包丢失、确认应答丢失
缺点:超时周期可能相对较长。
滑动窗口
TCP 利用滑动窗口实现流量控制的机制。滑动窗口(Sliding window)是⼀种流量控制技术。早期的网络通信中,通信双方不会考虑网络的拥挤情况直接发送数据。由于大家不不知道网络拥塞状况,同时发送数据,导致中间节点阻塞掉包,谁也发不不了了数据,所以就有了了滑动窗口机制来解决此问题。
TCP 中采用滑动窗口来进行传输控制,滑动窗口的大小意味着接收方还有多大的缓冲区可以用于接收数据。发送方可以通过滑动窗口的大小来确定应该发送多少字节的数据。当滑动窗口为 0 时,发送⽅方一般不能再发送数据报,但有两种情况除外,⼀一种情况是可以发送紧急数据,例如,允许用户终止在远端机上的运行进程。另一种情况是发送方可以发送一个 1 字节的数据报来通知接收方重新声明它希望接收的下⼀字节及发送方的滑动窗口大小。
流量控制
TCP 利用滑动窗口实现流量控制。流量控制是为了控制发送方发送速率,保证接收方来得及接收。接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送⽅的发送速率。将窗口字段设置为 0,则发送方不能发送数据。
拥塞控制
拥塞窗口 cwnd是发送方维护的一个的状态变量,它会根据网络的拥塞程度动态变化的。 我们在前面提到过发送窗口 swnd 和接收窗口 rwnd 是约等于的关系,那么由于加入了拥塞窗口的概念后,此时发送窗口的值是swnd = min(cwnd, rwnd),也就是拥塞窗口和接收窗口中的最小值。
TCP粘包
- 什么是TCP粘包问题?
TCP粘包就是指发送方发送的若干包数据到达接收方时粘成了一个包,从接收缓冲区来看,后一个后数据的头紧接着前一包数据的尾,出现粘包的原因是多方面的,可能是来自发送方,也可能是来自接收方的。
- 造成TCP粘包的原因?
- 发送方的原因 TCP默认使用Nagle算法(主要作用:减少网络中报文段的数量),而Nagle算法主要做两件事:
- 只有上一个分组得到确认,才会发送下一个分组;
- 收集多个小分组,在一个确认到来时一起发送。
Nagle算法造成了发送方可能会出现粘包问题。
- 接收方的原因
TCP接收到数据包时,并不会马上交到应用层进行处理,或者说应用层并不会立即处理。实际上,TCP将接收到的数据包保持在接收缓存里,然后应用程序主动从缓存读取收到的分组。这样一来,如果TCP接收数据包到缓存的速度大于应用程序程序中从缓存中读取数据包的速度,多个包就会被缓存,应用程序就有可能读取到多个首尾相接粘到一起的包。
- 什么时候需要处理粘包现象?
- 如果发送方发送的多组数据本来就是同一块数据的不同部分,比如说一个文件被分成多个部分发送,这时当然不需要处理粘包现象;
- 如果多个分组毫不相干,甚至是并列关系,那么这个时候就一定要处理粘包现象。
- 如何处理粘包现象?
- 发送方
对于发送方造成的粘包问题,可以通过关闭Nagle算法来解决,使用TCP_NODELAY选项来关闭算法。
- 接收方
接收方没有办法来处理粘包现象,只能将问题交给应用层来处理。
- 应用层
应用层的解决办法简单可行,不仅能解决接收方的粘包问题,还可以解决发送方的粘包问题。
解决办法:循环处理,应用程序从接收缓存中读取分组时,读完一条数据,就应该循环读取下一条数据,直到所有数据都被处理完成,但是如何判断每条数据的长度呢?
- 格式化数据:每条数据有固定的格式(开始符,结束符),这种方法简单易行,但是选择开发符合结束符时一定要确保每条数据的内部不包含开始符合结束符。
- 发送长度:发送每条数据时,将数据的长度一并发送,例如规定数据的前4位是数据的长度,应用层在处理时可以根据长度来判断每个分组的开发和结束位置。
TCP半包
半包问题是指,当发送的消息是 ABC 时,另一端却接收到的是 AB 和 C 两条信息,像这种情况就叫做半包。
半包的主要原因:
- 发送方每次写入数据 > 套接字(Socket)缓冲区大小;
- 发送的数据大于协议的 MTU (Maximum Transmission Unit,最大传输单元),因此必须拆包。
UDP
- 谈一谈TCP和UDP的区别?
- TCP是可靠传输,UDP是不可靠传输;
- TCP面向连接,UDP无连接;
- TCP传输数据有序,UDP不保证数据的有序性;
- TCP不保存数据边界,UDP保留数据边界;
- TCP传输速度相对UDP较慢;
- TCP有流量控制和拥塞控制,UDP没有;
- TCP是重量级协议,UDP是轻量级协议。
网络层
IP协议。