1.计算机网络体系结构
1.1 OSI体系结构
- 应用层
- 表示层:数据压缩、加密以及数据描述
- 会话层:建立及管理会话
- 运输层
- 网络层
- 数据链路层
- 物理层
1.2 TCP/IP体系结构
- 应用层
- 运输层
- 网际层
- 网络接口层
1.3 五层协议体系结构
- 应用层:为特定应用程序提供数据传输服务
- 运输层:为进程提供通用数据传输服务
- 网络层:为主机提供传输服务。把传输层传递下来的报文段或者用户数据封装成分组
- 数据链路层:为同一链路的主机提供数据传输服务,把网络层传下来的分组封装成帧
- 物理层:尽可能屏蔽传输媒体和通信手段的差异,使链路层感觉不到这些差异
2.网络层
2.1 ip地址
- 分类
1.A类:0开头,8位网络号,24位主机号
2.B类:10开头,16位网络号,16位主机号
3.C类:110开头,24位网络号,8位主机号
2.2 地址解析协议ARP
ARP实现由IP地址得到MAC地址。每个主机都有一个ARP高速缓存,里面有本局域网上的各主机和路由器的IP地址到MAC地址的映射表。当主机A欲向本局域网上的某个主机B发送IP数据报时,就先在其ARP高速缓存中查看有无主机B的IP地址,如果有则可以查到MAC地址,如果没有,此时主机A会通过广播的方式请求ARP分组,主机B收到该请求后会发送ARP相应分组给主机A告知MAC地址。
2.3 网际控制报文协议ICMP
为了有效转发IP和数据报和提高交付的机会。封装在ip数据报中,ping是其一个重要的应用,来测试两台主机之间的连通性。
Ping的原理是通过向目的主机发送ICMP Echo请求报文,目的主机收到之后会发送ICMP回答报文。Ping会根据时间和成功响应的次数估算出数据包往返时间和丢包率。
3.运输层
3.1 TCP
面向连接,提供可靠交付,有流量控制,拥塞控制,只能是一对一。
-
TCP首部:20个固定字节,包括序号、确认号、源端口、目的端口、数据偏移、确认ACK、同步SYN、终止FIN、窗口。
应用场景:效率要求低,准确率要求高的场景。如文件传输,接受邮件,远程登陆
- 三次握手(三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接):
- A向B发送SYN=1的连接请求,初始序号为X。
- B收到报文,如果同意,向A发送SYN=1,ACK=1的确认报文,确认号X+1,同时也选择一个初始序号Y
- A收到B的报文后,发送ACK=1确认报文,确认号Y+1,序号X+1。
- 三次握手的原因:第三次握手是为了防止失效连接请求到达服务器,让服务器错误打开连接。客户端发送的连接请求如果在网络中滞留,会隔很长时间才收到服务器返回的确认,客户端等待一个超时重传时间后,会重新发送连接请求,但这个滞留的请求最终还是会达到服务器,如果不进行三次握手,服务端会打开第二个连接。如果进行了三次握手,客户端会忽视服务器发来的滞留连接请求的确认。
- 四次挥手:
- A发送连接释放报文,FIN=1。
- B收到之后发出确认ACK=1,此时TCP处于半关闭状态,B可向A发送数据,A不可以发送
- B执行完接收操作,不再需要连接,发送连接释放报文,FIN=1,ACK=1。
- A收到后发出确认ACK=1,进入TIME-WAIT状态,等待两个最大报文存活时间后释放连接。
- 四次挥手的原因:客户端发送了释放连接的报文后,服务器收到报文就会进入到CLOSE-WAIT状态,这个状态是为了让服务器接收还未传送完的数据。
- 等待2MSL的原因:
1.确认最后一个报文到达服务端,如果没到达会重新发送
2.保证本连接内产生的报文全部从网络消失
3.2 TCP的可靠传输
- TCP给发送的每一个包进行编号,接收方对数据包进行排序,把有序数据传送给应用层。
- 校验和:TCP将保持它首部和数据的校验和。这是一个端到端的校验和,目的是检测数据在传输过程中的任何变化。如果收到段的校验和有差错,TCP将丢弃这个报文段和不确认收到此报文段。
- TCP的接收端会丢弃重复的数据。
- 流量控制
- 拥塞控制
- 超时重传:当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段,如果不能及时收到一个确认将重发这个报文段。
- ARQ协议
滑动窗口:TCP滑动窗口相当于是缓存的一部分,用来暂时存放字节流。窗口里面的都是未发送的或未确认的,如果发送并接收成功了,就右移滑动窗口。
流量控制:为了控制发送方发送速率,保证接收方来得及接收。通过接收方发送的确认报文中的窗口字段可以用来控制窗口大小,从而控制发送速率。
拥塞控制:如果网络出现拥塞,分组将会丢失,此时发送方会重传,从而导致网络拥塞度更高。所以需要减少数据的发送,通过慢开始、拥塞避免、快恢复、快重传来实现拥塞控制:
1.慢开始:发送最初执行慢开始,cwnnd(拥塞窗口)=1,收到确认后,cwnd翻倍,当cwnd>=ssthresh(慢开始门限),进入拥塞避免。
2.拥塞避免:每次收到确认后,cwnd不再翻倍,而是cwnd=cwnd+1,如果出现超时,ssthresh=cwnd/2,重新执行慢开始
3.快重传:在发送方,如果收到三个重复确认,此时立即执行快重传,立即重传下一个字段。
4.快恢复:如果只是丢失个别报文段,而不是网络拥塞,应执行快恢复,ssthresh=cwnd/2,cwnd=ssthresh,直接进入拥塞避免阶段。ARQ协议
1.停止等待ARQ协议:每发完一个分组就停止发送,等待对方确认。如果过了一段时间,还是没有收到确认,说明没有发送成功,需要重新发送,直到收到确认后再发下一个分组。若接收方收到重复分组,就丢弃该分组,但同时还要发送确认。优点是实现简单,缺点是信道利用率低,等待时间长。
2.连续ARQ协议:发送方维持一个发送窗口,凡位于发送窗口内的分组可以连续发送出去,而不需要等待对方确认。接收方一般采用累计确认,对按序到达的最后一个分组发送确认,表明到这个分组位置所有分组都已经正确收到了。优点是信道利用率高,容易实现,即使确认丢失,也不必重传。缺点是不能向发送方反映出接收方已经正确收到的所有分组的信息。TCP粘包:一个数据包中包含了发送端发送的两个数据包的信息,由于接收端不知道这两个数据包的界限,所以对于接收端很难处理。
TCP拆包:一个数据包拆成了多个。
解决方案:
1.使用带消息头的协议,消息头存储消息开始标识以及消息长度信息,服务端获取消息头的时候解析出消息长度,然后向后读取该长度的内容
2.设置定长消息
3.设置消息边界,服务端从网络流中按消息编辑分离出消息内容
3.3 UDP
无连接,没有阻塞控制,支持一对一,一对多,多对多。
- UDP首部:只有8个字节,包括源端口、目的端口、长度和校验和。12个字节的首部是为了计算检验和临时增加的。
- 应用场景:效率要求高,对准确性要求相对低的场景。如QQ聊天,在线视频,网络语音电话,广播通信
3.4 TCP与UDP的区别
- TCP面向连接,UDP是无连接的,在发送数据前不需要建立连接
- TCP提供可靠全双工的通信服务,UDP是半双工,只能单向传播
- 通过TCP连接可靠传输的数据,是可靠、无差错、不丢失、不重复且 按序到达的;UDP是不可靠信道,尽最大努力交付,不保证可靠交付
- TCP面向字节流,UDP面向报文
- TCP有拥塞控制,UDP没有
- TCP是点到点的,UDP支持一对一,一对多,多对多
- TCP首部开销20字节,UDP开销小,只有8字节
4.应用层
4.1 DNS
DNS是一个分布式数据库,提供了主机名和IP地址之间相互转换的服务。每个站点只保留它自己的那部分数据。DNS可以使用UDP或TCP传输,端口号为53,大多数情况下使用UDP,只有两种情况会使用TCP:
如果返回的响应超过512字节
区域传送(主域名服务器向辅助域名服务器传送变化的那部分数据)
DNS工作过程:
1.客户端提出域名解析请求,并将该请求发送给本地的域名服务器。
2.本地的域名服务器收到请求后,先查询本地缓存,如果有,直接返回对应的IP地址
3.如果没有该记录,则本地域名服务器就直接把请求发给根域名服务器,然后根域名服务器再返回给本地域名服务器一个所查询域的主域名服务器的地址
4.本地服务器向这个主域名服务器发送请求,接收请求的服务器查询自己的缓存,如果没有该记录,则返回相关下级的域名服务器的地址。
5.重复第四步,直到找到正确的记录
6.本地域名服务器获得地址后,将该地址存到缓存中,同时返回结果
4.2 文件传送协议FTP
使用TCP进行连接。需要两个连接来传送一个文件。
- 控制连接:服务器打开21端口等待客户端连接,客户端主动连接后,使用这个连接将客户端命令传给服务器,并传回服务器的应答。
- 数据连接:用来传送一个文件数据。
4.3 动态主机配置协议(DHCP)
DHCP提供了即插即用的联网方式,用户不再需要手动配置IP地址等信息。DHCP配置的内容不仅是IP地址,还包括子网掩码、网关IP地址。
- 工作过程:
- 客户端发送Discover报文,放入UDP中,该报文被广播到同一子网的所有主机上。如果客户端和DHCP服务器不在同一个子网,就需要使用中继代理。
- DHCP服务器收到Discover报文后,发送Offer报文给客户端,该报文包含了客户端所需要的信息,因此客户端需要进行选择。
- 如果客户端选择了某个DHCP服务器提供的信息,那么就发送Request报文给该DHCP服务器。
- DHCP服务器发送ACK报文,表示客户端此时可以使用提供给它的信息。
4.4 电子邮件协议
发送协议常用SMTP,读取协议常用POP3和IMAP。
4.5 电脑上访问一个web页面的过程
- DNS解析域名,得到对应的IP地址。主机向DNS服务器发送查询报文,此过程中,需要通过网关服务器的IP地址获得其MAC地址,这过程中需要通过ARP协议。路由器将DNS查询请求转发到DNS服务器,解析出IP地址。
- 建立TCP连接。得到了HTTP服务器的IP地址后,与HTTP服务器进行三次握手来建立TCP连接。
- HTTP请求。连接建立后,浏览器生成HTTP GET报文,交付给HTTP服务器。
- HTTP服务器从TCP套接字中读取HTTP GET报文,生成HTTP响应报文,将WEB页面内容放入报文主体中,返回给主机。
- 浏览器抽取WEB页面内容,进行渲染,显示出来。
5.HTTP
5.1 HTTP报文
- 请求报文
1.报文首部(请求行、请求首部字段、通用首部字段、实体首部字段、其他)
2.空行
3.报文主体 - 响应报文
1.报文首部(响应行、响应首部字段、通用首部字段、实体首部字段、其他)
2.空行
3.报文主体
5.2 状态码
100:请求正在处理,客户端可以继续发送请求或忽略这个响应
200:OK
204:请求已经成功处理,但是返回的响应报文不包含实体的主体部分。
301:永久性重定向
302:临时性重定向
303:临时性重定向,但要求客户端要用GET获取资源。
304:请求首部包含条件,如果不满足条件,则会返回304状态码
400:请求语法错误
401:表示发送的请求需要有认证信息
403:请求被拒绝
404:Not found
500:服务器正在执行请求时发生错误
5.3 短连接与长连接
- 长连接:只需要建立一次TCP连接就能进行多次HTTP通信,HTTP1.1后默认,如果要断开连接,使用Connection:close;
- 短连接:一次TCP连接只能进行一次HTTP通信,HTTP1.0默认。如果要使用长连接,使用Connection:keep-Alive。
5.4 Cookie和Session
- Cookie用来保存HTTP的状态信息。Cookie是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器之后向同一服务器再次发起请求时被携带上,用于告知服务端两个请求是否来自同一浏览器。
- Session存储在服务器端,使用Session维护用户登陆状态。
- 二者选择:
1.Cookie只能存储ASCII码字符串,而Session则可以存储任何类型的数据,因此在考虑数据复杂性时首选Session
2.Cookie存储在浏览器中,容易被恶意查看。如果非要将一些隐私数据存在Cookie中,可以将Cookie进行加密,然后在服务器进行解密。
3.对于大型网站,如果用户所有信息都存储在Session中,那么开销是很大的,因此不建议将所有的用户信息都存储到Session中。
5.5 HTTPS
HTTP的安全性问题:
1.使用明文通信,内容可能会被窃听
2.不验证通信方的身份,通信方的身份可能遭遇 伪装
3.无法验证明文的完整性,明文可能会被篡改HTTPS(加密、认证、完整性保护):HTTP先和SSL通信,再由SSL和TCP通信,也就是说HTTPS使用了隧道进行通信。
对称密钥加密:加密和解密都用同一密钥,运算速度快,无法安全地将密钥传输给对方
非对称密钥密钥:加密和解密使用不同的密钥,可以更安全地将公开密钥传输给通信发送方,运算速度慢
HTTPS采用混合的加密机制,使用非对称密钥加密用于传输对称密钥来保证传输过程的安全性,之后使用对称密钥加密进行通信来保证通信过程的效率。
缺点:速度慢、需要支付证书的昂贵费用
HTTPS建立连接的过程:
1.客户端向服务端发送支持的加密协议及版本,SSL\TLS等
2.服务端从中筛选适合的加密协议
3.服务端向客户端返回证书,证书中有公钥
4.客户端使用根证书验证证书合法性
5.客户端生成对称密钥,通过证书中的公钥加密,发送到服务器端
6.服务端使用私钥解密,获得对称密钥,使用对称密钥加密数据
7.客户端解密数据,SSL开始通信
5.6 HTTP/2.0
- HTTP/1.x的缺陷:
1.客户端需要多个连接才能实现并发和缩短延迟
2.不会压缩请求和响应首部,从而导致不必要的网络流量
3.不支持有效的资源优先级,致使底层TCP连接利用率低下。 - 二进制分帧层
HTTP/2.0将报文分成HEADERS帧和DATA帧,都是二进制格式的。在通信过程中,只会有一个TCP连接存在,它承载了任意数量的双向数据流。 - 服务端推送
在客户端请求一个资源时,会把相关资源一起发送给客户端,客户端就不需要再次发送请求了。例如请求一个.html文件,服务端会把相应的.css和.js文件一起发送。 - 首部压缩
使用霍夫曼编码对首部字段进行压缩。HTTP/2.0要求客户端和服务端同时维护和更新一个包含之前见过的首部字段表,避免了重复传输。
5.7 GET和POST的区别:
- 作用
GET用于获取资源,POST用于传输实体主体 - 参数
二者的请求都能使用额外的参数,但GET的参数是以查询字符串出现在URL中,而POST参数存储在实体主体中。URL只支持ASCII码,所以如果存在中文等字符就需要先编码。POST参数支持标准字符集 - 安全
安全的HTTP方法不会改变服务器的状态。因此GET方法是安全的。而POST传送的实体主体内容可能是用户上传的表单数据,上传成功之后,服务器可能把这个数据存储到数据库中,因此状态发生了改变。
同时,PUT\DELETE也是不安全的。 - 幂等性
同样的请求如果执行一次和执行多次的效果是一样的,服务器的状态也是一样的,那么就是具有幂等性的方法。所有安全的方法都是幂等的。 - 缓存性
GET是可缓存的,POST在多数情况下是不可缓存的。
6.I/O模型
一个输入操作,包括两个阶段,等待数据从网络中到达,从内核缓冲区复制到应用进程缓冲区
6.1 阻塞式I/O
第一阶段和第二阶段应用程序都被阻塞,只有完成了第二阶段才返回。但不影响其他进程的运行,所以对CPU的利用率高
6.2 NIO 非阻塞I/O
第一阶段不阻塞,需要不断执行系统调用来得知该阶段是否完成,这种方式是轮询(polling),第二阶段阻塞,此模型需要CPU处理更多的系统调用,所以CPU利用率低
6.3 信号驱动I/O
应用进程使用sigaction进行系统调用,内核立即返回,第一届都应用进程不阻塞,完成第一阶段后向应用进程发送SIGIO信号,然后进行第二阶段,该阶段是阻塞的。该方式比NIO的CPU利用率更高。
6.4 异步I/O
应用进程执行aio_read系统调用会立即返回,应用进程可以继续进行,不会阻塞,直到两个阶段都完成后,才会向应用进程发送信号。也就是两个阶段都不会阻塞。
6.5 I/O复用
使用select或者poll等待数据,并且可以等待多个套接字中任何一个变为可读。某个套接字可读时返回,再进行第二阶段。它的优点是让单个线程处理多个I/O,减少了线程创建和切换的开销。但两个阶段都是阻塞的。
- select
调用select会一直阻塞直到有描述符的事件到达或者等待时间超过TIMEOUT。有三种类型的描述符,readset、writeset、exceptset。select目前几乎在所有平台上都支持,缺点是单个进程能够监视描述符的数量存在最大限制,Linux上一般为1024。 - poll
不同于select使用三个描述符来表示的方式,poll使用一个pollfd的指针实现。其并没有最大数量的限制,poll返回后,需要轮询pollfd来获取就绪的描述符。 - select和poll的比较
1.select会修改描述符,poll不会
2.select描述符类型使用数组实现,单个进程能够监视描述符数量存在最大显示,默认为1024,而poll没有限制
3.poll提供了更多事件类型,并且对描述符的重复利用上比select高
4.二者每次调用都需要将全部描述符从应用进程缓存区复制到内核缓冲区。
5.二者都需要用轮询的方式获取就绪的描述符
6.几乎所有系统都支持select,只有比较新的系统支持poll - epoll
epoll是select和poll的增强版本。相较于select和poll来说,epoll更加灵活,没有描述符限制。epoll使用一个文件描述符管理多个描述符,将用户关系的文件描述符事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。
使用epoll_ctl()向内核注册新的描述符或者是改变某个文描述符的状态。已被注册的描述符在内核中会被维护在一颗红黑树上,通过回调函数内核会将I/O准备好的描述符加入到一个链表中管理,进程使用epoll_wait()便可以得到事件完成的描述符。 - epoll的工作模式
1.LT:当epoll_wait检测到描述符事件发生并将此事件通知应用程序,应用程序可以不立即处理该事件。下次调用epoll_wait时,会再次响应应用程序并通知此事件。同时支持阻塞和非阻塞套接字
2.ET:当epoll_wait检测到描述符事件发生立即将此事件通知应用程序,应用程序必须立即处理该事件。如果不处理,下次调用epoll_wait时,不会再次响应应用程序并通知此事件。ET模式很大程度上减少了epoll事件被重复触发的次数,因此效率比LT模式要高。在该模式工作下,必须使用非阻塞套接字,以避免一个文件句柄的阻塞读/写操作把处理多个文件描述符的任务饿死。 - 三者的应用场景
1.select:select的timeout参数精度为1ns,而其他的是1ms,因此select适用于实时性要求比较高的场景。
2.poll:在实时性要求不高的场景,且平台支持,应使用poll而不是select
3.epoll:运行在Linux平台上,有大量的描述符需要同时轮询,并且这些连接最好是长连接。如果同时监控小于1000,没有必要使用epoll。如果需要监控的描述符状态变化多且短暂,也没有必要用epoll。因为epoll中的所有描述符都存储在内核中,造成每次需要对描述符的状态改变都需要进行系统调用,频繁的调用降低效率。
7. Socket函数
- socket()函数:用于创建一个socket描述符,用于标记一个唯一的socket
- bind()函数:把一个地址族的特定地址赋给socket
- listen()函数:服务端监听socket
- connect()函数:客户端调用函数发出连接请求
- accept()函数:服务端监听到connect请求,调用accept()接收请求
- read()/write()函数:调用网络I/O进行读写操作
- close()函数:关闭连接