admin管理员组

文章数量:1548344

文章目录

  • RESTful
    • REST的指导原则
    • 资源
    • 资源方法
    • REST和HTTP不一样!!
  • ip地址、子网掩码、
  • 单机服务器最大并发的TCP连接数到底是多少
  • 带外数据和TCP紧急指针
  • linux主机同步文件
  • 两台主机输入同一个url地址出现页面不同可能的原因。
  • 为啥网络要分层设计
  • 数据传输速率
  • DNS域名解析的工作过程和原理
  • 一个机器的端口号上限,端口超过限制怎么办?
  • 单条记录高并发访问的优化
  • UDP如何实现可靠传输
  • TCP(UDP,IP)等首部的认识(http请求报文构成)
  • OSI七层协议及TCP/IP四层协议
  • MAC地址和IP地址
  • 对路由协议的了解与介绍。内部网关协议IGP包括RIP,OSPF,和外部网关协议EGP和BGP
  • ARP协议的作用
  • 网络层分片的原因与具体实现
  • ping命令的实现原理
  • traceroute发生了什么
  • UDP 和 TCP 的特点
      • 应用场景
  • TCP三次握手时的第一次的seq序号是怎样产生的
  • TCP三次握手/四次挥手
    • TCP三次握手
    • TCP 四次挥手
  • Tcp通信中服务器处理客户端意外断开
  • 服务器开发之大量time_wait 和 close_wait现象
  • 复位报文段RST
  • 优雅关闭和半关闭
      • close
      • shutdown
  • TCP如何保证可靠传输
  • TCP超时重传
  • tcp滑动窗口协议
  • TCP流量控制
  • TCP拥塞控制
    • 慢开始与拥塞避免
    • 快重传与快恢复
  • http协议与TCP的区别与联系
  • Http长连接和Keep-Alive以及Tcp的Keepalive
    • http的**Keep-Alive**
    • Tcp的Keepalive:
  • http/1.0和http/1.1的区别
  • HTTP状态码
  • http 常见字段
  • http的请求方法
    • GET 与 POST区别
  • get、put、post、delete含义与区别
  • 浏览器键入URL后的访问流程
  • 网页解析的过程与实现方法
  • Web浏览器与Web服务器之间的通信过程
  • HTTP协议
  • HTTP和HTTPS的区别
  • SSL
  • https的具体实现,怎么确保安全性
  • 浏览器如何验证HTTPS证书的合法性?
  • 运输层安全协议及SSL工作过程
    • HTTPS必须在每次请求中都要先在SSL/TLS层进行握手传输密钥吗?
  • HTTP2
  • Token
    • Web安全
  • cookie和session
    • cookie
    • session
    • 浏览器禁用cookie后,如何使用session?
  • HTTP持久连接与管线化
  • 什么是TCP粘包问题
    • 造成TCP粘包的原因
    • 如何处理粘包现象?
  • TCP/IP的粘包与避免介绍一下
  • TCP的封包和拆包
  • HTTP断点续传
  • IP/TCP/UDP分片
  • 短连接与长连接
  • 对称密码和公钥密码体制
  • 数字签名和数字证书
  • 消息摘要算法,MD5算法,为什么MD5是不可逆的,有什么办法可以加强消息摘要算法的安全性让它不那么容易被破解呢?
  • Syn Flood 攻击
  • CSRF与XSS
  • ARP欺骗
  • 打洞听说过吗?打洞是用什么协议实现的呢
    • 中继(Relaying)
    • 逆向连接(Connection reversal)
    • UDP打洞
    • TCP打洞

代理服务器又称万维网高速缓存,代理服务器把最近的一些请求和响应暂存在本地磁盘上。当新请求到达时,若代理服务器发现这个请求与暂存的请求相同,就返回暂存的响应。

RESTful

RESTful是一种架构的规范与约束、原则,符合这种规范的架构就是RESTful架构

RESTful 架构的核心规范与约束:统一接口

分为四个子约束:

  • 每个资源都拥有一个资源标识,每个资源的资源标识可以用来唯一地标明该资源
  • 消息的自描述性
  • 资源的自描述性。
  • HATEOAS Hypermedia As The Engine Of Application State(超媒体作为应用状态引擎)
    即客户只可以通过服务端所返回各结果中所包含的信息来得到下一步操作所需要的信息,如到底是向哪个URL发送请求等。也就是说,一个典型的REST服务不需要额外的文档标示通过哪些URL访问特定类型的资源,而是通过服务端返回的响应来标示到底能在该资源上执行什么样的操作

目的:实现客户端无需借助任何文档即能调用到所有的服务器资源

REST的指导原则

  1. 客户端 - 服务器 - 通过将用户接口问题与数据存储问题分开,我们通过简化服务器组件来提高跨多个平台的用户接口的可移植性并提高可伸缩性。
  2. 无状态 - 从客户端到服务器的每个请求都必须包含理解请求所需的所有信息,并且不能利用服务器上任何存储的上下文。因此,会话状态完全保留在客户端上。
  3. 可缓存 - 缓存约束要求将对请求的响应中的数据隐式或显式标记为可缓存或不可缓存。如果响应是可缓存的,则客户端缓存有权重用该响应数据以用于以后的等效请求。
  4. 统一接口 - 通过将通用性的软件工程原理应用于组件接口,简化了整个系统架构,提高了交互的可见性。为了获得统一的接口,需要多个架构约束来指导组件的行为。REST由四个接口约束定义:资源识别; 通过陈述来处理资源; 自我描述性的信息; 并且,超媒体作为应用程序状态的引擎。
  5. 分层系统 - 分层系统风格允许通过约束组件行为来使体系结构由分层层组成,这样每个组件都不能“看到”超出与它们交互的直接层。
  6. 按需编码(可选) - REST允许通过以小程序或脚本的形式下载和执行代码来扩展客户端功能。这通过减少预先实现所需的功能数量来简化客户端。

资源

REST中信息的关键抽象是一种资源。可以命名的任何信息可以是资源:文档或图像,临时服务,其他资源的集合,非虚拟对象(例如,人)等。REST使用资源标识符来标识组件之间交互中涉及的特定资源。

任何特定时间戳的资源状态称为资源表示。表示由数据,描述数据的元数据和超媒体链接组成,这些链接可以帮助客户转换到下一个期望的状态。

表示的数据格式称为**媒体类型**。媒体类型标识定义如何处理表示的规范。真正的RESTful API看起来像*超文本*。每个可寻址信息单元明确地(例如,链接和id属性)或隐式地(例如,从媒体类型定义和表示结构导出)携带地址。

根据罗伊菲尔丁的说法:

超文本(或超媒体)意味着信息和控制同时呈现,使得信息成为用户(或自动机)通过其获得选择和选择动作的可供性。请记住,超文本不需要是浏览器上的HTML(或XML或JSON)。机器在理解数据格式和关系类型时可以跟踪链接。

此外,资源表示应该是自描述的:客户端不需要知道资源是员工还是设备。它应该基于与资源相关的媒体类型。因此在实践中,您最终将创建大量自定义媒体类型 - 通常是与一种资源相关联的一种媒体类型。

每种媒体类型都定义了默认处理模型。例如,HTML定义了超文本的呈现过程以及每个元素周围的浏览器行为。它与资源方法GET / PUT / POST / DELETE / …没有任何关系,除了一些媒体类型元素将定义一个过程模型,其类似于“具有href属性的锚元素创建一个超文本链接,当被选中时,在与CDATA编码的href属性对应的URI上调用检索请求(GET)。“

资源方法

与REST相关的其他重要事项是用于执行所需转换的资源方法。许多人错误地将资源方法与HTTP GET / PUT / POST / DELETE方法联系起来。

Roy Fielding从未提及任何关于在哪种情况下使用哪种方法的建议。他所强调的是它应该是统一的接口。如果你决定HTTP POST将用于更新资源 - 而不是大多数人推荐HTTP PUT - 它没关系,应用程序接口将是RESTful。

理想情况下,更改资源状态所需的所有内容都应该是该资源的API响应的一部分 - 包括方法以及它们将保留表示的状态。

应输入REST API,除了初始URI(书签)和适用于目标受众的标准化媒体类型集之外没有任何先验知识(即,任何可能使用API的客户都应该理解)。从那时起,所有应用程序状态转换必须由客户端选择服务器提供的选择来驱动,这些选择存在于接收的表示中或者由用户对这些表示的操纵所暗示。转换可以由客户端对媒体类型和资源通信机制的知识来确定(或限制),这两者都可以在运行中(例如,按需代码)进行改进。
[失败在这里意味着带外信息驱动交互而不是超文本。]

在构建RESTful API时,另一件可以帮助您的是基于查询的API结果应该由带有摘要信息的链接列表表示,而不是由原始资源表示的数组表示,因为查询不能代替资源标识。

REST和HTTP不一样!!

很多人更喜欢将HTTP与REST进行比较。REST和HTTP不一样。

REST!= HTTP

但是,由于REST还打算使web(互联网)更加简化和标准化,他主张更严格地使用REST原则。这就是人们试图开始将REST与网络(HTTP)进行比较的地方。Roy fielding在他的论文中没有提到任何实现指令 - 包括任何协议首选项和HTTP。到时候,您正在遵循REST的6个指导原则,您可以将您的接口称为RESTful。

简而言之,在REST架构风格中,数据和功能被视为资源,并使用统一资源标识符(URI)进行访问。通过使用一组简单,定义明确的操作来执行资源。客户端和服务器通过使用标准化接口和协议(通常是HTTP)来交换资源的表示

资源与其表示分离,以便可以以各种格式访问其内容,例如HTML,XML,纯文本,PDF,JPEG,JSON等。例如,可以使用和使用关于资源的元数据来控制高速缓存,检测传输错误,协商适当的表示格式,以及执行认证或访问控制。最重要的是,与资源的每次交互都是无状态的。

所有这些原则都有助于RESTful应用程序简单,轻量和快速。

ip地址、子网掩码、

  • IP地址:电脑IP,可以说是网络上的电脑识别号,有IP的电脑才能上网,方便大家的交流和寻找作用

  • 子网掩码:互联网是由许多小型网络构成的,每个网络上都有许多主机,这样便构成了一个有层次的结构。IP地址在设计时就考虑到地址分配的层次特点,将每个IP地址都分割成网络号和主机号两部分,以便于IP地址的寻址操作

子网掩码不能单独存在,它必须结合IP地址一起使用。子网掩码只有一个作用,就是将某个IP地址划分成网络地址和主机地址两部分。

  • 默认网关:一个网络就必须有网关,也就是internet网进入一个集体、或个体网络的最先接连者,有它我们的信息将能更好的得到规划。

  • 网关:只有设置好网关的IP地址,TCP/IP协议才能实现不同网络之间的相互通信

  • 网络号:用ip地址和子网掩码的二进制数进行“与”运算即可得出网络号。

  • 广播地址(Broadcast Address)是专门用于同时向网络中所有工作站进行发送的一个地址。

    在使用TCP/IP 协议的网络中,主机标识段host ID 为全1 的IP 地址为广播地址,广播的分组传送给host ID段所涉及的所有计算机。例如,对于10.1.1.0 (255.255.255.0 )网段,其广播地址为10.1.1.255 (255 即为2 进制的11111111 ),当发出一个目的地址为10.1.1.255 的分组(封包)时,它将被分发给该网段上的所有计算机。

单机服务器最大并发的TCP连接数到底是多少

文件句柄限制

在linux下编写网络服务器程序的朋友肯定都知道每一个tcp连接都要占一个文件描述符,一旦这个文件描述符使用完了,新的连接到来返回给我们的错误是“Socket/File:Can’t open so many files”。

这时你需要明白操作系统对可以打开的最大文件数的限制。

进程限制

执行 ulimit -n 输出 1024,说明对于一个进程而言最多只能打开1024个文件,所以你要采用此默认配置最多也就可以并发上千个TCP连接。临时修改:ulimit -n 1000000,但是这种临时修改只对当前登录用户目前的使用环境有效,系统重启或用户退出后就会失效。

重启后失效的修改(某些系统可能重启后并不会失效),编辑 /etc/security/limits.conf 文件, 修改后内容为:

soft nofile 1000000

hard nofile 1000000

永久修改:编辑/etc/rc.local,在其后添加如下内容:

ulimit -SHn 1000000

全局限制

执行cat /proc/sys/fs/file-nr 输出 9344 0 592026,分别为:

\1. 已经分配的文件句柄数,

\2. 已经分配但没有使用的文件句柄数,

\3. 最大文件句柄数。

但在kernel 2.6版本中第二项的值总为0,这并不是一个错误,它实际上意味着已经分配的文件描述符无一浪费的都已经被使用了 。

我们可以把这个数值改大些,用 root 权限修改 /etc/sysctl.conf 文件:

fs.file-max = 1000000

net.ipv4.ip_conntrack_max = 1000000

net.ipv4filter.ip_conntrack_max = 1000000

端口号范围限制

操作系统上端口号1024以下的端口是系统保留的,1024-65535是用户可用的,我们知道每个TCP连接都会用掉一个端口,所以网上铺天盖地的文章都在说单机服务器能支持最多的TCP连接是60000+,你是不是也这样认为呢?

TCP如何标识一个连接

这个问题,可能你会说,TCP是用四元组(也有人说是五元组,五元组相比于四元组多了协议,下面都说四元组)来标识一个连接,这四元组是【local ip, local port,remote ip,remote port】,我们单机作为服务器的时候,bind(port)的时候绑定了一个端口,然后就在等待着accept,没有再消耗其他端口资源,由此发现,65535并不是单机服务器了连接数的限制因素。

我们服务器代码中总是先listen然后再accept,你有没有注意到这两个方法都会返回一个文件句柄socketfd,你想过这两个socketfd的区别吗?

listen的socketfd是调用socket生成的,该socketfd是告诉TCP/IP协议栈这个socketfd指向绑定的[IP:PORT],以后有请求[IP:PORT]的数据都发给这个socketfd,所以listen的socketfd就是表示服务器的绑定信息。

accept返回的socketfd是标识当前连接四元组的【local ip, local port,remote ip,remote port】,作用是表示谁跟我正连接着呢,我发送接收数据的来源和目的地是什么。其中与服务器绑定的local ip, local port是不变的,变化的是不同的客户端的remote ip,remote port。

所以我们得出结论:影响单机服务器最大并发连接数的因素是客户端的ip和port。

服务器最大连接数到底是多少

server通常固定在某个本地端口上监听,等待client的连接请求。不考虑地址重用(unix的SO_REUSEADDR选项)的情况下,即使server端有多个ip,本地监听端口也是独占的,因此server端tcp连接4元组中只有remote ip(也就是client ip)和remote port(客户端port)是可变的,因此最大tcp连接为客户端ip数×客户端port数,对IPV4,不考虑ip地址分类等因素,最大tcp连接数约为2的32次方(ip数)×2的16次方(port数),也就是server端单机最大tcp连接数约为2^48。

带外数据和TCP紧急指针

传输层协议使用带外数据(out-of-band,OOB)来发送一些重要的数据,如果通信一方有重要的数据需要通知对方时,协议能够将这些数据快速地发送到对方.为了发送这些数据,协议一般不使用与普通数据相同的通道,而是使用另外的通道.linux系统的套接字机制支持低层协议发送和接受带外数据.但是TCP协议没有真正意义上的带外数据.为了发送重要协议,TCP提供了一种称为紧急模式(urgentmode)的机制.TCP协议在数据段中设置URG位,表示进入紧急模式.接收方可以对紧急模式采取特殊的处理.很容易看出来,这种方式数据不容易被阻塞,可以通过在我们的服务器端程序里面捕捉SIGURG信号来及时接受数据或者使用带OOB标志的recv函数来接受.

linux主机同步文件

Linux服务器之间同步文件使用:*rsync* 命令

rsync和scp区别:用rsync做文件的复制要比scp的速度快,rsync只对差异文件做更新。scp是把所有文件都复制过去。

两台主机输入同一个url地址出现页面不同可能的原因。

答:token不同,cookie不同,本机对url缓存解析不同。这之中又问了问cookie和session,DNS解析的过程等

为啥网络要分层设计

为了为了简化网络设计的复杂性,通信协议采用分层的结构,各层协议之间既相互独立又相互高效的协调工作。对于复杂的通信协议,其结构应该是采用层次的。分层的协议可以带来很多便利:
分层的好处有:

  • 一灵活性好:当任何一层发生变化时,只要层间接口关系保持不变,则在这层以上或以下各层均不受影响。此外,对某一层提供的服务还可进行修改。当某层提供的服务不再需要时,甚至可以将这层取消,更容易管理。

  • 二各层之间是独立的:在各层间标准化接口,允许不同的产品只提供各层功能的一部分,某一层不需要知道它的下一层是如何实现的,而仅仅需要知道该层通过层间的接口所提供的服务。由于每一层只实现一种相对独立的功能,所以比较容易实现!

数据传输速率

数据传输速率(每秒传输二进制信息的位数),单位是位/秒 bps或b/s,

计算公式: R=1/T×log2N(bps)

  • T为一个数字脉冲信号的宽度(全宽码)或重复周期(归零码)单位为秒;

  • N为一个码元(一个数字脉冲称为码元)所取的离散值个数。

DNS域名解析的工作过程和原理

端口号:53

DNS 是一个分布式数据库,提供了主机名和 IP 地址之间相互转换的服务。这里的分布式数据库是指,每个站点只保留它自己的那部分数据。

DNS解析有两种方式:递归查询和迭代查询

  • 递归查询 用户先向本地域名服务器查询,如果本地域名服务器的缓存没有IP地址映射记录,就向根域名服务器查询,根域名服务器就会向顶级域名服务器查询,顶级域名服务器向权限域名服务器查询,查到结果后依次返回。
  • 迭代查询 用户向本地域名服务器查询,如果没有缓存,本地域名服务器会向根域名服务器查询,根域名服务器返回顶级域名服务器的地址,本地域名服务器再向顶级域名服务器查询,得到权限域名服务器的地址,本地域名服务器再向权限域名服务器查询得到结果

DNS域名解析的过程:

  • 打开浏览器,输入一个域名。比如输入www.163,这时,主机会发出一个DNS请求到本地DNS服务器。地DNS服务器会首先查询它的缓存记录,如果缓存中有此条记录,就可以直接返回结果。如果没有,本地DNS服务器还要向DNS根服务器进行查询。

  • 根DNS服务器没有记录具体的域名和IP地址的对应关系,而是告诉本地DNS服务器,你可以到域服务器上去继续查询,并给出域服务器的地址。

  • 本地DNS服务器继续向域服务器发出请求,在这个例子中,请求的对象是域服务器。域服务器收到请求之后,也不会直接返回域名和IP地址的对应关系,而是告诉本地DNS服务器,你的域名的解析服务器的地址。

  • 最后,本地DNS服务器向域名的解析服务器发出请求,收到一个域名和IP地址对应关系,本地DNS服务器不仅要把IP地址返回给用户电脑,还要把这个对应关系保存在缓存中,以备下次别的用户查询时,可以直接返回结果,加快网络访问。

DNS采用UDP传输

一次UDP名字服务器交换可以短到两个包:一个查询包、一个响应包。一次TCP交换则至少包含9个包:三次握手初始化TCP会话、一个查询包、一个响应包以及四次分手的包交换。

考虑到效率原因,TCP连接的开销大得,故采用UDP作为DNS的运输层协议

在两种情况下会使用 TCP 进行传输:

  • 如果返回的响应超过的 512 字节(UDP 最大只支持 512 字节的数据)。
  • 区域传送(区域传送是主域名服务器向辅助域名服务器传送变化的那部分数据)。

一个机器的端口号上限,端口超过限制怎么办?

65536.因为TCP的报文头部中源端口号和目的端口号的长度是16位,也就是可以表示2^16=65536个不同端口号,因此TCP可供识别的端口号最多只有65536个。但是由于0到1023是知名服务端口,所以实际上还要少1024个端口号。

而对于服务器来说,可以开的端口号与65536无关,其实是受限于Linux可以打开的文件数量,并且可以通过MaxUserPort来进行配置。

单条记录高并发访问的优化

服务器端:

  • 使用缓存,如redis等
  • 使用分布式架构进行处理
  • 将静态页面和静态资源存储在静态资源服务器,需要处理的数据使用服务器进行计算后返回
  • 将静态资源尽可能在客户端进行缓存
  • 采用ngnix进行负载均衡 (nginx读作恩静埃克斯 = Engine X)

数据库端:

  • 数据库采用主从赋值,读写分离措施
  • 建立适当的索引
  • 分库分表

UDP如何实现可靠传输

因为UDP是无连接的协议,所以在传输层上无法保证可靠传输,要想实现可靠传输,只能从应用层实现。需要实现seq/ack机制,重传机制和窗口确认机制。

就要接收方收到UDP之后回复个确认包,发送方有个机制,收不到确认包就要重新发送,每个包有递增的序号,接收方发现中间丢了包就要发重传请求,当网络太差时候频繁丢包,防止越丢包越重传的恶性循环,要有个发送窗口的限制,发送窗口的大小根据网络传输情况调整,调整算法要有一定自适应性

TCP(UDP,IP)等首部的认识(http请求报文构成)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fGZzB0c6-1649154398316)(J:\面试\2021.2.16\pic\watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjkwNTE0MQ==,size_16,color_FFFFFF,t_70#pic_center)]

TCP的头部大致包括:源端口,目的端口,序号,确认号,偏移位,标志位,校验和等等

UDP的头部则包括:源端口,目的端口,长度,校验和。

IP数据包的头部包括:源IP地址,目的IP地址,协议,校验和,总长度等等

每个udp包的最大大小是多少?
65507 约等于 64K

为什么最大是65507?
因为udp包头有2个byte用于记录包体长度. 2个byte可表示最大值为: 2^16-1=64K-1=65535
udp包头占8字节, ip包头占20字节, 65535-28 = 65507

如果要发送的udp报文大于65507怎么办?
需要在应用层由开发者自己分片发送. 分片的粒度最大65507字节. 系统的sendto函数是不支持大于65507字节的单包发送的.

OSI七层协议及TCP/IP四层协议

路由器* 工作在第三层(网络层),而我们常说的交换机* 工作在第二层(链路层)

路由器:寻址,转发(依靠 IP 地址)
交换机:过滤,转发(依靠 MAC 地址)

路由器内有一份路由表,里面有它的寻址信息(就像是一张地图),它收到网络层的数据报后,会根据路由表和选路算法将数据报转发到下一站(可能是路由器、交换机、目的主机)

交换机内有一张MAC表,里面存放着和它相连的所有设备的MAC地址,它会根据收到的数据帧的首部信息内的目的MAC地址在自己的表中查找,如果有就转发,如果没有就放弃
每一个路由器与其之下连接的设备,其实构成一个局域网
交换机工作在路由器之下,就是也就是交换机工作在局域网内

  • 交换机用于局域网内网的数据转发
  • 路由器用于连接局域网和外网

它们两个可不可以少一个?

交换机在局域网内工作,它根据 MAC 地址转发数据,如果没有了路由器在网络层寻址,那么我们的数据就不能发送到其他网络终端上去了

路由器内集成了交换机的功能,主机与路由器相连也可以实现数据转发,但是不足之处是:
可扩展的接口不如交换机多
交换机通常由硬件加速转发,路由器主要靠软件寻址,速度慢

  • 七层协议:物、数、网、传、会、表、应

    • 物理层 RJ45

    • 数据链路层 PPP,IEEE 802.3/802.2

    • 网络层 IP,ARP:

      主要任务:把分组从源端传到目的端,为分组交换网上的不同主机提供通信服务。网络传输单元:数据报。

      • 路由选择与分组转发
      • 异构网络互联
      • 拥塞控制
    • 传输层 TCP,UDP

      • 为应用进程之间提高端到端的逻辑通信,网络层为主机之间提高逻辑通信。
      • 运输层还要对收到的报文进行差错检测,IP数据报首部的检验和字段,只检验首部是否差错而不检查数据部分。
      • 运输层需要有两种不同的运输协议,即面向连接的TCP和无连接的UDP。
    • 会话层

    • 表示层 TIFF,GIF,JPEG,

    • 应用层 DNS,HTTP,FTP

      应用层提供各种各样的应用层协议,这些协议嵌入在各种我们使用的应用程序中,为用户与网络之间提供一个打交道的接口。

  • 四层协议:数据链路层(物理层,数据链路层),网络层(网络层),传输层(传输层),应用层(会话层,表示层,应用层)

    • 数据链路层: PPP MAC不属于协议,只是一个地址
    • 网络层:IP、ARP、ICMP
    • 传输层:TCP、UDP
    • 应用层:DNS、HTTP、FTP

MAC地址和IP地址

  • MAC地址又叫硬件地址或物理地址,它不是地址位置,实际上是适配器地址,每一台计算机中固化在适配器的ROM中的地址,作用是用来定义网络设备的位置
  • IP地址是IP协议提供的一种统一的地址格式,为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异
  • 两者的区别
    • 物理地址是数据链路层和物理层使用的地址,放在MAC帧的首部
    • IP地址是网络层和以上各层使用的地址,放在IP数据报的首部

对路由协议的了解与介绍。内部网关协议IGP包括RIP,OSPF,和外部网关协议EGP和BGP

RIP“路由信息协议(Route Information Protocol)”的简写,主要传递路由信息,通过每隔30秒广播一次路由表,维护相邻路由器的位置关系,同时根据收到的路由表信息使用动态规划的方式计算自己的路由表信息。RIP是一个距离矢量路由协议,最大跳数为16跳,16跳以及超过16跳的网络则认为目标网络不可达。

OSPF:详见:https://zhuanlan.zhihu/p/41341540

ARP协议的作用

网络层使用的是IP地址,数据链路层使用的是硬件地址。
ARP协议的用途是为了从网络层使用的IP地址,解析出数据链路层使用的硬件地址。

  • 在主机ARP高速缓存中存放一个从IP地址到硬件地址的映射表
  • 当需要解析时,先去arp缓存表(存着ip-mac对应关系)去查找目标ip的mac地址
  • 如果查到了,将目标ip的mac地址封装到链路层数据报
  • 如果缓存中没有找到,会发起一个广播:who is ip XXX tell ip XXX,所有收到的广播的机器看这个ip是不是自己的,如果是自己的,则以单播的形式将自己的mac地址回复给请求的机器

数据链路层:

把网络层交下来的Ip数据包添加首部和尾部封装成帧

网络层分片的原因与具体实现

https://blog.csdn/gettogetto/article/details/72851734

因为在链路层中帧的大小通常都有限制,比如在以太网中帧的最大大小(MTU)就是1500字节。如果IP数据包加上头部后大小超过1500字节,就需要分片。

IP分片和完整IP报文差不多拥有相同的IP头,16位ID域对于每个分片都是一致的,这样才能在重新组装的时候识别出来自同一个IP报文的分片。在IP头里面,16位识别号唯一记录了一个IP包的ID,具有同一个ID的IP分片将会重新组装;而13位片偏移则记录了某IP片相对整个包的位置;而这两个表中间的3位标志则标志着该分片后面是否还有新的分片。这三个标志就组成了IP分片的所有信息(将在后面介绍),接受方就可以利用这些信息对IP数据进行重新组织。

IPv4:

  • 16位标识:唯一标识主机发送的每一个数据报,其值由系统随机生成,每发送一个数据报,其值加1.该值在数据包分片时被分片到每一个分片中。一个数据报的所有分片具有相同的标识位

  • 13位分片偏移:是分片相对于原始Ip数据报开始处的偏移。实际的偏移值是该值左移3位(乘以8)得到的

    除了最后一个分片外,每个分片的数据部分的长度必须是8的整数倍(这样才能保证最后一个分片拥有一个合适的偏移值)

  • 8位生存时间TTL:数据报到达目的地之前允许经过的路由器的跳数。

    常见设置64,每经过一个路由器减1.当TTL值为0,路由器丢弃报文,并向源端发送一个ICMP差错报文。TTL值可以防止路由器陷入路由循环。

  • 16位头部检验和:由头部端填充,接收端使用CRC算法检验IP数据报头部在传输过程是否损坏

ping命令的实现原理

ping主要是为了测试两台主机之间的连通性,通过应用层直接使用网络层ICMP,没有通过运输层TCP和UDP,是通过发送ICMP报文回显请求实现。

ICMP协议不包含端口信息的,端口信息在数据传输层定义。

  • A主机构建一个ICMP格式的数据包,通过ICMP协议把该数据包和B主机的IP地址一起交给IP协议;

  • 然后IP协议就会构建一个IP数据报,并且在映射表中查找目的IP对应的mac地址,将其交给数据链路层,构建一个数据帧,附上源mac地址和目的mac地址发送出去。

    • 数据包(A主机的IP地址+控制信息+B主机的IP地址)

    • IP协议会根据B主机的IP地址和自己的子网掩码判断是不是属于同一层网络,如果是属于同一层网络的话,就会获得目的主机的MAC地址,如果以前两机有过通信,在A机的ARP缓存表应该有构建一个数据帧主机IP与其MAC的映射关系,如果没有,就发一个ARP请求广播,得到目的主机的MAC

  • 目的主机接收到数据帧后,就会检查包上的mac地址与本机mac是否相符,如果相符,就接收并把其中的信息提取出来交给IP协议,IP协议就会将其中的信息提取出来交给ICMP协议。然后构建一个ICMP应答包,用相同的过程发送回去。

traceroute发生了什么

traceroute用来跟踪一个分组从源点到终点的路径,及到达其中每一个路由器的往返时间

  • 通过发送UDP报文,设置目的端口为一个不可能的值
  • 将IP首部中的TTL分别设置从1到N,每次逐个增加
  • 每次设置TTL后,重新发送数据报,路由器接收到数据报后,将TTL减1,若当前的路由器接收到数据报,发现TTL为1时,会将TTL减1变为0,然后丢弃数据报,发送ICMP时间超过报文
  • 如果最后一个数据报刚刚达到主机,数据报的TTL是1,此时主机不把TTL减1
  • 因IP数据报中封装的是无法交付的UDP数据报,此时目的主机向源主机发送ICMP终点不可达差错报文,表示达到目的主机

UDP 和 TCP 的特点

  • 用户数据报协议 UDP(User Datagram Protocol)是无连接的,尽最大可能交付,没有拥塞控制,面向报文(对于应用程序传下来的报文不合并也不拆分,只是添加 UDP 首部),支持一对一、一对多、多对一和多对多的交互通信。
  • 传输控制协议 TCP(Transmission Control Protocol)是面向连接的,提供可靠交付,有流量控制,拥塞控制,提供全双工通信,面向字节流(把应用层传下来的报文看成字节流,把字节流组织成大小不等的数据块),每一条 TCP 连接只能是点对点的(一对一)。
  • 连接

    • TCP是面向连接的传输层协议,即传输数据之前必须先建立好连接。
    • UDP无连接。
  • 服务对象

    • TCP是点对点的两点间服务,即一条TCP连接只能有两个端点
    • UDP支持一对一,一对多,多对一,多对多的交互通信。
  • 可靠性

    • TCP是可靠交付:无差错,不丢失,不重复,按序到达。
    • UDP是尽最大努力交付,不保证可靠交付。
  • 拥塞控制,流量控制

    • TCP有拥塞控制和流量控制保证数据传输的安全性。
    • UDP没有拥塞控制,网络拥塞不会影响源主机的发送效率。
  • 报文长度

    • TCP是动态报文长度,即TCP报文长度是根据接收方的窗口大小和当前网络拥塞情况决定的,流式传输
    • UDP面向报文,不合并,不拆分,保留上面(应用层)传下来报文的边界,直接传输报文。
  • 首部开销

    • TCP首部开销大,首部20个字节。
    • UDP首部开销小,8字节。(源端口,目的端口,UDP数据报长度,检验和,每个字段两个字节)

应用场景

  • 要求通信数据完整性,则应该选用TCP协议(如文件传输、重要状态的更新,登录数据传输等)
  • 要求通信实时性,使用 UDP 协议(如视频传输,通话,屏幕共享软件)

TCP三次握手时的第一次的seq序号是怎样产生的

第一次的序号是随机序号,但也不是完全随机,它是使用一个ISN算法得到的。

seq = C + H (源IP地址,目的IP地址,源端口,目的端口)。其中,C是一个计时器,每隔一段时间值就会变大,H是消息摘要算法,输入是一个四元组(源IP地址,目的IP地址,源端口,目的端口)

TCP三次握手/四次挥手

ACK SYN FIN解释及是否消耗序列号

  • ACK 确认标志位,ACK可以携带数据,若不携带,则不消耗序列号
  • SYN 同步标志位,SYN不能携带数据,必须消耗一个序列号
  • FIN 终止标志位,FIN可以携带数据,必须消耗一个序列号

TCP数据报首部的关键字段:

  • 确认号 4byte;即期望收到对方下一个报文段的第一个数据字节的序号,若确认号为N,则表明:到序号N-1为止的所有数据都已正确收到。

  • 同步SYN(SYNchronization)===> 1bit;在连接建立时用来同步序号

  • 终止FIN(FINis)===> 用来释放一个连接

  • 复位RST(ReSeT)===> 1bit;当RST=1时,表明TCP连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。RST置1还用来拒绝一个非法的报文段或拒绝打开一个连接。RST也可称为重建位或重置位。

TCP三次握手

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gRyqL3j5-1649154398319)(./pic/三次握手.png)]

SYN-SENT(同步已发送)

SYN-RCVD(同步已发送)

假设 A 为客户端,B 为服务器端。

  • 首先 B 处于 LISTEN(监听)状态,等待客户的连接请求。
  • A 向 B 发送连接请求报文,SYN=1,ACK=0,选择一个初始的序号 x。
  • B 收到连接请求报文,如果同意建立连接,则向 A 发送连接确认报文,SYN=1,ACK=1,确认号为 x+1,同时也选择一个初始的序号 y。
  • A 收到 B 的连接确认报文后,还要向 B 发出确认,ACK=1,确认号为 y+1,序号为 x+1。
  • B 收到 A 的确认后,连接建立。

服务器端给客户端发送同步及确认报文时可以合并,四次会浪费时间

三次握手原因:
第三次握手是为了防止失效的连接请求到达服务器,让服务器建立错误连接。

客户端发送的连接请求如果在网络中滞留,那么就会隔很长一段时间才能收到服务器端发回的连接确认。客户端等待一个超时重传时间之后,就会重新请求连接。但是这个滞留的连接请求最后还是会到达服务器,如果不进行三次握手,那么服务器就会打开两个连接。如果有第三次握手,客户端会忽略服务器之后发送的对滞留连接请求的连接确认,不进行第三次握手,因此就不会再次打建立连接。

TCP 四次挥手

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BJI4QPje-1649154398321)(./pic/四次挥手.png)]

ACK 在连接建立之后都为 1。

  • A 发送连接释放报文,FIN=1 ,seq=u。

  • B 收到之后发出确认,ACK=1,seq=v,ack=u+1,此时 TCP 属于半关闭状态,B 能向 A 发送数据但是 A 不能向 B 发送数据。

  • 若B已经没有向A发送的数据,B发出连接释放报文段,主动关闭TCP连接。FIN=1,seq=w,重复上次已发送确认号ack=u+1。

  • A 收到 B的连接释放,发送以确认报文段,再时间等待计时器设置的2MSL(最长报文段寿命)后,连接彻底关闭。ACK=1,seq=u+1,ack=w+1。

四次挥手的原因

客户端发送了 FIN 连接释放报文之后,服务器收到了这个报文,就进入了 CLOSE-WAIT 状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕之后,服务器会发送 FIN 连接释放报文

MSL:最长报文段寿命,一般为2分钟

MTU:最大传输单元(Maximum Transmission Unit,MTU)用来通知对方所能接受数据服务单元的最大尺寸

MSS (网络传输数据最大值)的时候,用 MTU 减去网络层报头长度以及传输层报头长度即可。

TIME_WAIT

客户端接收到服务器端的 FIN 报文后进入此状态,此时并不是直接进入 CLOSED 状态,还需要等待一个时间计时器设置的时间 2MSL(最长保报文寿命)。这么做有两个理由:

  • 确保客户端发送的最后一个确认报文能够到达。如果 服务器没收到 A客户端发送来的确认报文,那么就会重新发送连接释放请求报文,A 等待一段时间就是为了处理这种情况的发生。
  • 等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。

为什么TIME_WAIT的时间是2MSL?

TIME_WAIT至少需要持续2MSL时长,这2个MSL中的第一个MSL是为了等自己发出去的最后一个ACK从网络中消失,而第二MSL是为了等在对端收到ACK之前的一刹那可能重传的FIN报文从网络中消失。

  • 为了可靠地实现全双工连接的终止,假设图2-5中客户端发送的最后一个ACK丢失,服务端将重传FIN,为了能够收到这个超时重传的FIN,客户端需要TIME_WAIT状态;那TIME_WAIT状态就必须是2MSL了吗?其实这个要看服务端FIN的超时重传时间RTO,如果RTO小于MSL,那TIME_WAIT状态MSL就够了,如果RTO大于2MSL那么TIME_WAIT状态2MSL也是不够的,所以只有RTO在MSL和2MSL之间的时候,TIME_WAIT状态存在的理由1才是TIME_WAIT的时间是2MSL的原因。其实一般情况下,RTO都是远远小于MSL的,但考虑到最糟糕的情况,RTO是为2MSL,所以TIME_WAIT状态为2MSL可以保证最糟糕情况也可以收到超时重传的FIN

  • 为了保证本连接持续的时间所产生的所有分组都从网络中消失,也就是保证新建立一个TCP连接时,来自该连接老的重复分组都已经在网络中消失了。这里可能有的人会有个疑问:客户端回复最后一个ACK之后,感觉一个MSL就可以所有分组消失了啊,为什么还要2MSL所有分组才消失呢

    假设客户端发送ACK刚刚过了一个MSL时间,而服务端在收到这个ACK之前一瞬间刚好启动超时重传FIN,所以要等这个FIN也消失,就是2MSL了。文中所指的另一个方向的应答应该就是这个超时重传的FIN。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SO5IdFbO-1649154398322)(./pic/客户端-服务器的套接字函数.png)]

connect:调用connect函数将激发三次握手,仅在连接建立成功或出错时才返回

listen:listen函数把套接字从CLOSING转为LISTEN状态

  • 队列:
    • 未完成连接队列:SYN分节已发出并到达服务器。这些套接字处于SYN_RCVD
    • 已完成连接队列:套接字处于ESTABLISHED状态,已完成三次握手。

accept:由TCP服务器调用,用于从已完成连接队列头返回下一个已完成连接。如果已完成连接队列为空,进程会睡眠(套接字默认阻塞),成功返回一个代表客户端的文件描述符。

Tcp通信中服务器处理客户端意外断开

为了处理客户端异常断线,常服务端/客户端 需要发送心跳,及时清理掉断线用户,但服务端的心跳时间间隔不要设置得太小,否则容易导致客户端掉线频率增加。具体抓包结果如下:

  • 服务端A发送包x给客户端B,B回ACK,但由于网络原因ACK未到达A,A重发x,B回ACK,A又未收到,这样几次后,A重发次数超过了TCP最大重发次数,于是A发送RST给B复位此链接,导致B断线!!!因此,若心跳间隔太小,则A

  • 发给客户端的包的频率越高,导致客户端异常断线的概率就越大

意外断开,是客户端(多指支持3G的移动设备)并没有正常关闭socket,双方并未按照协议上的四次挥手去断开连接,一般的处理办法都是利用保活机制。而保活机制分又可以让底层实现也可自己实现

一、双方拟定心跳(自实现)

一般由客户端发送心跳包,服务端并不回应心跳,只是定时轮询判断一下与上次的时间间隔是否超时(超时时间自己设定)。服务器并不主动发送是不想增添服务器的通信量,减少压力。

  • 情况1:客户端由于某种网络延迟等原因很久后才发送心跳(它并没有断),这时服务器若利用自身设定的超时判断其已经断开,而后去关闭socket。若客户端有重连机制,则客户端会重新连接。若不确定这种方式是否关闭了原本正常的客户端,则在ShutDown的时候一定要选择send,表示关闭发送通道,服务器还可以接收一下,万一客户端正在发送比较重要的数据呢,是不?

  • 情况2:客户端很久没传心跳,确实是自身断掉了。在其重启之前,服务端已经判断出其超时,并主动close,则四次挥手成功交互。

  • 情况3:客户端很久没传心跳,确实是自身断掉了。在其重启之前,服务端的轮询还未判断出其超时,在未主动close的时候该客户端已经重新连接。

    • 这时候若客户端断开的时候发送了FIN包,则服务端将会处于CLOSE_WAIT状态;

    • 这时候若客户端断开的时候未发送FIN包,则服务端处还是显示ESTABLISHED状态;

      而新连接上来的客户端(也就是刚才断掉的重新连上来了)在服务端肯定是ESTABLISHED;这时候就有个问题,若利用轮询还未检测出上条旧连接已经超时(这很正常,timer总有个间隔吧),而在这时,客户端又重复的上演情况3,那么服务端将会出现大量的假的ESTABLISHED连接和CLOSE_WAIT连接。

      最终结果就是新的其他客户端无法连接上来,但是利用netstat还是能看到一条连接已经建立,并显示ESTABLISHED,但始终无法进入程序代码。个人最初感觉导致这种情况是因为假的ESTABLISHED连接和CLOSE_WAIT连接会占用较大的系统资源,程序无法再次创建连接(因为每次我发现这个问题的时候我只连了10个左右客户端却已经有40多条无效连接)。而最近几天测试却发现有一次程序内只连接了2,3个设备,但是有8条左右的虚连接,此时已经连接不了新客户端了。这时候我就觉得我想错了,不可能这几条连接就占用了大量连接把,如果说几十条还有可能。但是能肯定的是,这个问题的产生绝对是设备在不停的重启,而服务器这边又是简单的轮询,并不能及时处理,暂时还未能解决。

    二、利用KeepAlive

    在S和C建立连接后,若双方均不发送数据只保持连接,则再两小时后(这个时间我未测试过,但很多资料都显示是这个间隔,貌似是默认的)系统会自动启动保活机制向peer发送包,看对方是否回应ack,若可以收到则继续保持,否则无效。这也就能解释如下现象了:

    现象1:

    自己写的socket程序放在pc机上(2台),为了模拟意外断掉,将客户端的网线拔掉,点击任何一方去发送都发送不了(这肯定么),那么你认为这时连接已经断了吗?非也,tcp连接并没有断,因为双方还不知道对方是否已经断掉(保活机制还未启动呢),这时若查看netstat,发现状态很已然是ESTABLISHED;当过一段时间后将客户端的网线插好,则可以继续发送。

    现象2:

    根据现象1的描述,感觉当电脑意外断网的时候,在短时间内又恢复时,QQ的自动连接也应该是这样。

服务器开发之大量time_wait 和 close_wait现象

首先通过TCP的四次挥手过程分析确定两个状态的出现背景。TIMEWAIT是大量tcp短连接导致的,确保对方收到最后发出的ACK,一般为2MSL;CLOSEWAIT是tcp连接不关闭导致的,出现在close()函数之前。

  • 被动断开连接的一方在发送完ACK包之后就会进入CLOSE_WAIT状态.

  • 它需要服务器在发送完剩余数据之后,就调用close来关闭连接.此时服务器从CLOSE_WAIT状态变为LAST_ACK状态.

如果服务器或客户端存在大量的TIME_WAIT状态,这是一种可能是正常的情况,主动断开连接的一方会进入TIME_WAIT状态.

TIMEWAIT

主动连接端会占用本地端口,大量的TIME_WAIT状态的socket,会占用大量的本地端口,当本地端口不足时,tcp连接不能建立成功。可以通过以下两种方式来解决上述问题

  • 可以通过设置SOCKET选项SO_REUSEADDR来重用处于TIMEWAIT的sock地址,对应于内核中的tcp_tw_reuse,这个参数不是“消除” TIME_WAIT的,而是说当资源不够时,可以重用TIME_WAIT的连接

  • 修改ipv4.ip_local_port_range,增大可用端口范围,来承受更多TIME,但这样效果有限。

  • 设置SOCK选项SO_LINGER选项,这样会直接消除TIMEWAIT

通常情况下,客户端的端口资源比较充足,应该让客户端主动断开连接,但在某些场景下,如tcp连接长时间没有IO操作,应该将此空闲tcp连接踢除,否则空闲tcp会占有系统各个资源却不干事,太浪费了

CLOSEWAIT

close_wait状态是在TCP四次挥手的时候收到FIN但是没有发送自己的FIN时出现的,服务器出现大量close_wait状态的原因有两种:

  • 客户端主动关闭,而服务端没有close关闭连接,则服务端产生大量CLOSEWAIT;一般是业务代码问题,如还有数据需要发送;或者服务器的业务逻辑有问题,没有执行close()方法

    当recv的返回值为0时(对端主动关闭连接),会跳出while(1)循环,此时正确做法是调用close关闭tcp连接,将close(connfd)这句代码注释掉,注释后服务器对于客户端发送的FIN包不会做回应,一直保持close_wait状态。

  • 服务器的父进程派生出子进程,子进程继承了socket,收到FIN的时候子进程处理但父进程没有处理该信号,导致socket的引用不为0无法回收

处理方法:

  • 停止应用程序
  • 修改程序里的bug

复位报文段RST

  • 访问不存在的端口

    它将产生一个ICMP端口不可达的信息.

  • 异常终止连接

    终止一个连接的正常方式是发送FIN,所有排队数据都已发送后才发送FIN,正常情况没有数据丢失

    异常释放:发送复位报文段而不是FIN来释放一个连接.

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bWFScxBx-1649154398324)(/home/xiaohu/.config/Typora/typora-user-images/image-20200831152004735.png)]

  • 检测半关闭连接

    当某端崩溃退出,此时对端并不知道,若往对端发送数据,会响应一个RST复位报文段

    若果一方已经关闭或异常终止连接而另一方还不知道,这样的TCP连接称为半打开…

    只要不打算在半打开连接上传输数据,仍处于连接状态的一方就不会检测两一方已经出现异常.

优雅关闭和半关闭

  • 一个文件描述符关联一个文件,这里是网络套接字。
  • close会关闭用户应用程序中的socket句柄,释放相关资源,从而触发关闭TCP连接
  • 关闭TCP连接,是关闭网络套接字,断开连接
  • close只是减少引用计数,只有当引用计数为0的时候,才发送fin,真正关闭连接
  • shutdown不同,只要以SHUT_WR/SHUT_RDWR方式调用即发送FIN包
  • shutdown后要调用close
  • 保持连接的某一端想关闭连接了,但它需要确保要发送的数据全部发送完毕以后才断开连接,此种情况下需要使用优雅关闭,一种是shutdown,一种是设置SO_LINGER的close
  • 半关闭,是关闭写端,但可以读对方的数据,这种只能通过shutdown实现

close

close函数会关闭文件描述符,不会立马关闭网络套接字,除非引用计数为0,则会触发调用关闭TCP连接。

  • 检查接收缓冲区是否有数据未读(不包括FIN包),如果有数据未读,协议栈会发送RST包,而不是FIN包。如果套接字设置了SO_LINGER选项,并且lingertime设置为0,这种情况下也会发送RST包来终止连接。其他情况下,会检查套接字的状态,只有在套接字的状态是TCP_ESTABLISHED、TCP_SYN_RECV和TCP_CLOSE_WAIT的状态下,才会发送FIN包
  • 若有多个进程调用同一个网络套接字,会将网络套接字的文件描述符+1,close调用只是将当前套接字的文件描述符-1,只会对当前的进程有效,只会关闭当前进程的文件描述符,其他进程同样可以访问该套接字
  • close函数的默认行为是,关闭一个socket,close将立即返回,TCP模块尝试把该socket对应的TCP缓冲区中的残留数据发送给对方,并不保证能到达对方
  • close行为可以通过SO_LINGER修改
struct linger{
    int l_onoff;    //开启或关闭该选项
    int l_linger;   //滞留时间
}
  • l_onoff为0,该选项不起作用,采用默认close行为
  • l_onoff不为0
    • l_linger为0,close立即返回,TCP模块丢弃被关闭的socket对应的TCP缓冲区中的数据,给对方发送RST复位信号,这样可以异常终止连接,且完全消除了TIME_WAIT状态
    • l_linger不为0
      • 阻塞socket,被关闭的socket对应TCP缓冲区,若还有数据,close会阻塞,进程睡眠,直到收到对方的确认或等待l_linger时间,若超时仍未收到确认,则close返回-1设置errno为EWOULDBLOCK
      • 非阻塞socket,close立即返回,需要根据返回值和errno判断残留数据是够发送完毕

shutdown

shutdown没有采用引用计数的机制,会影响所有进程的网络套接字,可以只关闭套接字的读端或写端,也可全部关闭,用于实现半关闭,会直接发送FIN包

  • SHUT_RD,关闭sockfd上的读端,不能再对sockfd文件描述符进行读操作,且接收缓冲区中的所有数据都会丢弃
  • SHUT_WR,关闭写端,确保发送缓冲区中的数据会在真正关闭连接之前会发送出去,不能对其进行写操作,连接处于半关闭状态
  • SHUT_RDWR,同时关闭sockfd的读写

TCP如何保证可靠传输

TCP协议如何保证可靠传输

TCP协议保证数据传输可靠性的方式主要有:

  • 校验和:包括首部和数据2部分

    发送的数据包的二进制相加然后取反,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP将丢弃这个报文段和不确认收到此报文段。

  • 确认应答+序列号(累计确认+seq)

    • 接收方收到报文就会确认(累积确认:对所有按序接收的数据的确认)

    • TCP给发送的每一个包进行编号,接收方对数据包进行排序,把有序数据传送给应用层

  • 超时重传

    当TCP发出一个段后,它启动一个定时器等待目的端确认收到这个报文段如果不能及时收到一个确认,将重发这个报文段

  • 流量控制

    TCP连接的每一方都有固定大小的缓冲空间,TCP的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP使用的流量控制协议是可变大小的滑动窗口协议。

    接收方有即时窗口(滑动窗口),随ACK报文发送

  • 拥塞控制

    当网络拥塞时,减少数据的发送。

    发送方有拥塞窗口,发送数据前比对接收方发过来的即使窗口,取小

    慢启动、拥塞避免、拥塞发送、快速恢复

TCP超时重传

  • 保证了数据的可靠传输,对于一些出错,丢包等问题TCP设计了超时与重传机制。
  • 基本原理:在发送一个数据之后,就开启一个定时器,并设置RTO,若是在这个时间内没有收到发送数据的ACK确认报文,则对该报文进行重传,在达到一定次数还没有成功时放弃并发送一个复位信号。
  • 不同的网络情况不一样,不可能设置一样的RTO(超时重传时间),实际中RTO是根据网络中的RTT(报文段往返时间)来自适应调整的

tcp滑动窗口协议

详见 TCP-IP详解:滑动窗口SlidingWindow和TCP滑动窗口

TCP的滑动窗口用来控制接收方和发送方的发送速率,避免拥塞的发生。滑动窗口其实就是接收端的缓冲区大小,用来告诉发送方对它发送的数据有多大的缓冲空间。在接收方的滑动窗口已知的情况下,当接收方确认了连续的数据序列之后,发送方的滑动窗口向后滑动,发送下一个数据序列。

接收方会在每个ACK数据包中附带自己当前的接受窗口(滑动窗口)的大小,方便发送方进行控制。

TCP流量控制

流量控制是为了控制发送方发送速率,保证接收方来得及接收。

  • 如果发送方的发送速率太快,会导致接收方处理不过来,这时候接收方只能把处理不过来的数据存在缓存区里(失序的数据包也会被存放在缓存区里)

  • 如果缓存区满了发送方还在疯狂着发送数据,接收方只能把收到的数据包丢掉,大量的丢包会极大着浪费网络资源

接收方每次收到数据包,可以在发送确定报文的时候,同时告诉发送方自己的缓存区还剩余多少是空闲的,我们也把缓存区的剩余大小称之为接收窗口大小,用变量win来表示接收窗口的大小。

发送方收到之后,便会调整自己的发送速率,也就是调整自己发送窗口的大小,当发送方收到接收窗口的大小为0时,发送方就会停止发送数据,防止出现大量丢包情况的发生

发送方何时再继续发送数据?

当发送方收到接受窗口 win = 0 时,这时发送方停止发送报文,并且同时开启一个定时器,每隔一段时间就发个测试报文去询问接收方,打听是否可以继续发送数据了,如果可以,接收方就告诉他此时接受窗口的大小;如果接受窗口大小还是为0,则发送方再次刷新启动定时器。

发送窗口和接受窗口相等吗?

接收方在发送确认报文的时候,会告诉发送发自己的接收窗口大小,而发送方的发送窗口会据此来设置自己的发送窗口,但这并不意味着他们就会相等。首先接收方把确认报文发出去的那一刻,就已经在一边处理堆在自己缓存区的数据了,所以一般情况下接收窗口 >= 发送窗口。

接收方累积确认,发送方超时重传。

TCP拥塞控制

拥塞控制:防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。
如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但是出发点不同。流量控制是为了让接收方能来得及接收,而拥塞控制是为了降低整个网络的拥塞程度。

慢开始与拥塞避免

判断网络拥塞出现超时

慢开始思路:当主机开始发送数据时,并不清楚网络负载情况,如果立即把大量字节注入网络,会引起网络拥塞,较好方法从小到大逐渐增大发送窗口。

发送的最初执行慢开始,逐渐增大拥塞窗口值,令 cwnd = 1,发送方只能发送 1 个报文段;当收到确认后,将 cwnd 加倍,因此之后发送方能够发送的报文段数量为:2、4、8 …

注意到慢开始每个轮次都将 cwnd 加倍,这样会让 cwnd 增长速度非常快,从而使得发送方发送的速度增长速度过快,网络拥塞的可能性也就更高。

设置一个慢开始门限 ssthresh,当 cwnd >= ssthresh 时,进入拥塞避免,每个轮次只将 cwnd 加 1。

如果出现了超时,则令 ssthresh = cwnd / 2,同时拥塞窗口cwnd=1,然后重新执行慢开始。

快重传与快恢复

在接收方,要求每次接收到报文段都应该对最后一个已收到的有序报文段进行确认。例如已经接收到 M1 和 M2,此时收到 M4,应当发送对 M2 的确认。

快重传:在发送方,如果收到三个重复确认,那么可以知道下一个报文段丢失,此时执行快重传,立即重传下一个报文段。例如收到三个 M2,则 M3 丢失,立即重传 M3。

在这种情况下,只是丢失个别报文段,而不是网络拥塞。因此执行**快恢复,**令调整门限值ssthresh = cwnd / 2 ,cwnd = ssthresh,注意到此时直接进入拥塞避免。

慢开始和快恢复的快慢指的是 cwnd 的设定值,而不是 cwnd 的增长速率。慢开始 cwnd 设定为 1,而快恢复 cwnd 设定为 ssthresh。

几种经典的拥塞控制算法:

  • Vegas:Vegas将时延RTT的增加作为网络出现拥塞的信号,RTT增加,拥塞窗口减小,RTT减小,拥塞窗口增加

  • Reno:Reno将拥塞控制的过程分为四个阶段:慢启动、拥塞避免、快重传和快恢复,是现有的众多拥塞控制算法的基础

  • Cubic:Cubic是Linux内核2.6之后的默认TCP拥塞控制算法,使用一个立方函数

  • BBR:BBR是谷歌在2016年提出的一种新的拥塞控制算法

http协议与TCP的区别与联系

联系:Http协议是建立在TCP协议基础之上的,当浏览器需要从服务器获取网页数据的时候,会发出一次Http请求。Http会通过TCP建立起一个到服务器的连接通道,当本次请求需要的数据传输完毕后,Http会立即将TCP连接断开,这个过程是很短的。

区别:HTTP和TCP位于不同的网络分层。TCP是传输层的协议,定义的是数据传输和连接的规范,而HTTP是应用层的,定义的是数据的内容的规范。
建立一个TCP请求需要进行三次握手,而由于http是建立在tcp连接之上的,建立一个http请求通常包含请求和响应两个步骤

Http长连接和Keep-Alive以及Tcp的Keepalive

http的Keep-Alive

  • 非Keep-Alive模式时,每个请求/应答,客户端和服务器都要新建一个连接,完成之后立即断开连接;
  • 当使用Keep-Alive模式时,Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接。

开启Keep-Alive的优缺点:
优点:Keep-Alive模式更加高效,因为避免了连接建立和释放的开销。
缺点:长时间的Tcp连接容易导致系统资源无效占用,浪费系统资源。

当保持长连接时,如何判断一次请求已经完成?
Content-Length
Content-Length表示实体内容的长度。浏览器通过这个字段来判断当前请求的数据是否已经全部接收。
所以,当浏览器请求的是一个静态资源时,即服务器能明确知道返回内容的长度时,可以设置Content-Length来控制请求的结束。但当服务器并不知道请求结果的长度时,如一个动态的页面或者数据,Content-Length就无法解决上面的问题,这个时候就需要用到Transfer-Encoding字段。

Transfer-Encoding
Transfer-Encoding是指传输编码,在上面的问题中,当服务端无法知道实体内容的长度时,就可以通过指定Transfer-Encoding: chunked来告知浏览器当前的编码是将数据分成一块一块传递的。当然, 还可以指定Transfer-Encoding: gzip, chunked表明实体内容不仅是gzip压缩的,还是分块传递的。最后,当浏览器接收到一个长度为0的chunked时, 知道当前请求内容已全部接收。

Tcp的Keepalive:

连接建立之后,如果客户端一直不发送数据,或者隔很长时间才发送一次数据,当连接很久没有数据报文传输时如何去确定对方还在线,到底是掉线了还是确实没有数据传输,连接还需不需要保持,这种情况在TCP协议设计中是需要考虑到的。
TCP协议通过一种巧妙的方式去解决这个问题,当超过一段时间之后,TCP自动发送一个数据为空的报文(侦测包)给对方,如果对方回应了这个报文,说明对方还在线,连接可以继续保持,如果对方没有报文返回,并且重试了多次之后则认为链接丢失,没有必要保持连接。

tcp keep-alive是TCP的一种检测TCP连接状况的保鲜机制。tcp keep-alive保鲜定时器,支持三个系统内核配置参数:
net.ipv4.tcp_keepalive_intvl = 15
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_time = 1800
keepalive是TCP保鲜定时器,当网络两端建立了TCP连接之后,闲置(双方没有任何数据流发送往来)了tcp_keepalive_time后,服务器就会尝试向客户端发送侦测包,来判断TCP连接状况(有可能客户端崩溃、强制关闭了应用、主机不可达等等)。如果没有收到对方的回答(ack包),则会在 tcp_keepalive_intvl后再次尝试发送侦测包,直到收到对方的ack,如果一直没有收到对方的ack,一共会尝试 tcp_keepalive_probes次,每次的间隔时间在这里分别是15s, 30s, 45s, 60s, 75s。如果尝试tcp_keepalive_probes,依然没有收到对方的ack包,则会丢弃该TCP连接。TCP连接默认闲置时间是2小时,一般设置为30分钟足够了。

http/1.0和http/1.1的区别

HTTP 协议老的标准是 HTTP/1.0 ,目前最通用的标准是 HTTP/1.1 。
HTTP1.0 只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个 TCP 连接,但是最新的http/1.0加入了长连接,只需要在客户端给服务器发送的http报文头部加入Connection:keep-alive
HTTP 1.1 支持持久连接,默认进行持久连接,在一个 TCP 连接上可以传送多个 HTTP 请求和响应,减少了建立和关闭连接的消耗和延迟。

HTTP状态码

  • 1XX:信息性状态码,表示接收的请求正在处理

    100 Continue :表明到目前为止都很正常,客户端可以继续发送请求或者忽略这个响应。

  • 2XX:表示服务器成功处理了客户端的请求

    • 200 OK:表示一切正常,如果非HEAD请求,服务器返回的响应头会有body数据
    • 204 No Content:请求已经成功处理,但是返回的响应报文不包含实体的主体部分。一般在只需要从客户端往服务器发送信息,而不需要返回数据时使用。
    • 206 Partial Content :应用于 HTTP 分块下载或断电续传,表示客户端进行了范围请求,响应报文包含由 Content-Range 指定范围的实体内容
  • 3XX 重定向:表示客户端请求的资源发送了变动,需要客户端用新的 URL 重新发送请求获取资源

    • 301 Moved Permanently表示永久重定向,说明请求的资源已经不存在了,需改用新的 URL 再次访问。

    • 302 Found表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问。

    301 和 302 都会在响应头里使用字段 Location,指明后续要 跳转的 URL,浏览器会自动重定向新的 URL。

    • 304 Not Modified不具有跳转的含义,表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,用于缓存控制。
  • 4xx 类状态码:表示客户端发送的报文有误,服务器无法处理,也就是错误码的含义

    • 400 Bad Request :请求报文中存在语法错误。

    • 401 Unauthorized :该状态码表示发送的请求需要有认证信息(BASIC 认证、DIGEST 认证)。如果之前已进行过一次请求,则表示用户认证失败。

    • 403 Forbidden :表示服务器禁止访问资源,并不是客户端的请求出错

    • 404 Not Found:表示请求的资源在服务器上不存在或未找到,所以无法提供给客户

  • 5xx 类状态码:表示客户端请求报文正确,但是服务器处理时内部发生了错误,属于服务器端的错误码

    • 500 Internal Server Error :服务器正在执行请求时发生错误。
    • 503 Service Unavailable :服务器暂时处于超负载或正在进行停机维护,现在无法处理请求

http 常见字段

  • Host:客户端发送请求时,用来指定服务器的域名

  • Content-Length 字段:服务器在返回数据时,会有 Content-Length 字段,表明本次回应的数据长度

  • Connection:常用于客户端要求服务器使用 TCP 持久连接,以便其他请求复用

HTTP/1.1 版本的默认连接都是持久连接,但为了兼容老版本的 HTTP,需要指定 Connection 首部字段的值为 Keep-Alive

Connection: keep-alive

一个可以复用的 TCP 连接就建立了,直到客户端或服务器主动关闭连接。但是,这不是标准字段

  • Content-Type

Content-Type 字段用于服务器回应时,告诉客户端,本次数据是什么格式

Content-Type: text/html; charset=utf-8

上面的类型表明,发送的是网页,而且编码是UTF-8

客户端请求的时候,可以使用 Accept 字段声明自己可以接受哪些数据格式

Accept: */*
  • Content-Encoding

Content-Encoding 字段说明数据的压缩方法。表示服务器返回的数据使用了什么压缩格式

Content-Encoding: gzip

表示服务器返回的数据采用了 gzip 方式压缩,告知客户端需要用此方式解压。

客户端在请求时,用 Accept-Encoding 字段说明自己可以接受哪些压缩方法

Accept-Encoding: gzip, deflate

http的请求方法

  • put:由于自身不带验证机制,任何人都可以上传文件,因此存在安全性问题,一般不使用该方法。

  • head:和 GET 方法类似,但是不返回报文实体主体部分。主要用于确认 URL 的有效性以及资源更新的日期时间等

  • DELETE:与 PUT 功能相反,并且同样不带验证机制。

  • OPTIONS:查询针对请求URL指定的资源支持的方法,会返回 Allow: GET, POST, HEAD, OPTIONS 这样的内容。

  • CONNECT:要求在与代理服务器通信时建立隧道,实现用隧道协议进行TCP通信。

    主要使用 SSL(Secure Sockets Layer,安全套接层)和 TLS(Transport Layer Security,传输层安全)协议把通信内容加密后经网络隧道传输。

  • TRACE:让Web服务器将之前的请求通信环回给客户端的方法

    • 发送请求时,在 Max-Forwards 首部字段中填入数值,每经过一个服务器就会减 1,当数值为 0 时就停止传输。

    • 通常不会使用 TRACE,并且它容易受到 XST 攻击(Cross-Site Tracing,跨站追踪)。

GET 与 POST区别

HTTP的请求方法包括GET,POST,PUT,DELETE四种基本方法。(四种方法中只有POST不是操作幂等性的)

  • Get 方法的含义是请求从服务器获取资源,这个资源可以是静态的文本、页面、图片视频等,POST方法则是相反操作,它向URI指定的资源提交数据,数据就放在报文的 body 里

  • Get是不安全的,很可能你的一些操作会被第三方看到,而Post的所有操作多用户来说是不可见的。

  • Get传输的数据量小,长度限制为4k,主要是因为它受约于URL长度的限制,而Post可以传输大量的数据,所以我们在传文件的时候会用Post。

    浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)但是不同浏览器不一定是产生两个TCP包

  • post可以传输二进制编码的信息,get的参数一般只支持ASCII

使用场景

​ 一般对于登录、注册等表单请求,不建议用GET方式请求,一般用POST,因为一些参数信息暴露出来会不安全。另外,对于博客、论坛、数据的上传下载等也最好用POST,因为论坛或者上传下载等前后都可能会产生数据的变化,故用POST。 而一般对于有响应速度要求,并且对信息相对不敏感的,比如查询、搜索等,可以使用GET

get、put、post、delete含义与区别

1、GET请求会向数据库发索取数据的请求,从而来获取信息,该请求就像数据库的select操作一样,只是用来查询一下数据,不会修改、增加数据,不会影响资源的内容,即该请求不会产生副作用。无论进行多少次操作,结果都是一样的。

2、PUT请求是向服务器端发送数据的,从而改变信息,该请求就像数据库的update操作一样,用来修改数据的内容,但是不会增加数据的种类等,也就是说无论进行多少次PUT操作,其结果并没有不同。

3、POST请求同PUT请求类似,都是向服务器端发送数据的,但是该请求会改变数据的种类等资源,就像数据库的insert操作一样,会创建新的内容。几乎目前所有的提交操作都是用POST请求的。

4、DELETE请求顾名思义,就是用来删除某一个资源的,该请求就像数据库的delete操作。

就像前面所讲的一样,既然PUT和POST操作都是向服务器端发送数据的,那么两者有什么区别呢。。。POST主要作用在一个集合资源之上的(url),而PUT主要作用在一个具体资源之上的(url/xxx),通俗一下讲就是,如URL可以在客户端确定,那么可使用PUT,否则用POST。

浏览器键入URL后的访问流程

  • 浏览器使用DNS协议向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址,其中DNS服务器是基于UDP的,因此会用到UDP协议;
  • 解析出 IP 地址后,根据该 IP 地址和默认端口 80,和服务器建立TCP连接,会使用到TCP协议;
  • 然后浏览器就要与服务器建立一个http连接,因此要用到http协议,http生成一个get请求报文,如果采用https还会使用https协议对http数据进行加密,涉及到SSL协议,将报文发送到TCP层
  • TCP层如果有需要先将HTTP数据包分片,分片依据MTU和MSS( mtu是网络传输最大报文包,mss是网络传输数据最大值)。
  • TCP的数据包然后会发送给IP层,用到IP协议。IP层通过路由选路,一跳一跳发送到目的地址。
  • 当然在一个网段内的寻址是通过以太网协议实现,以太网协议需要知道目的IP地址的物理地址,则需要ARP协议
  • 服务器端接收到请求,然后发送返回响应请求
  • 释放 TCP连接(若connection为close,则释放TCP连接,若为keep-alive则不会释放);
  • 浏览器将该解析html文本并显示内容

网页解析的过程与实现方法

这里仅展示浏览器解析服务器响应的过程,URL解析和交互的完整过程在(9)

  • 首先是html文档解析,浏览器会将html文档生成解析树,也就是DOM树,它由dom元素以及属性节点组成。
  • 然后浏览器加载过程中如果遇到了外部css文件或者图片资源,还会另外发送请求来获取css文件和资源,这个请求通常是异步的,不会影响html文档的加载。
  • 不过如果浏览器在加载时遇到了js文件,则会挂起渲染的线程,等待js文件加载解析完毕才恢复html的渲染线程。
  • 然后是css解析,将css文件解析为样式表对象来渲染DOM树

Web浏览器与Web服务器之间的通信过程

HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤:

  • 建立TCP连接
    在HTTP工作开始之前,Web浏览器首先要通过网络与Web服务器建立连接,该连接是通过TCP来完成的,该协议与IP协议共同构建Internet, 即著名的TCP/IP协议族,因此Internet又被称作是TCP/IP网络。HTTP是比TCP更高层次的应用层协议,根据规则,只有低层协议建立之 后才能,才能进行更层协议的连接,因此,首先要建立TCP连接,一般TCP连接的端口号是80。
  • web浏览器向web服务器发送请求命令
    一旦建立了TCP连接,Web浏览器就会向Web服务器发送请求命令。
  • web浏览器发送请求头信息
    浏览器发送其请求命令之后,还要以头信息的形式向Web服务器发送一些别的信息,之后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送。
  • Web服务器应答
    客户机向服务器发出请求后,服务器会客户机回送应答, HTTP/1.1 200 OK ,应答的第一部分是协议的版本号和应答状态码。
  • Web服务器发送应答头信息
    正如客户端会随同请求发送关于自身的信息一样,服务器也会随同应答向用户发送关于它自己的数据及被请求的文档。
  • Web服务器向浏览器发送数据
    Web服务器向浏览器发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据。
  • Web服务器关闭TCP连接
    一般情况下,一旦Web服务器向浏览器发送了请求数据,它就要关闭TCP连接,然后如果浏览器或者服务器在其头信息加入了这行代码:
      Connection:keep-alive
      TCP连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽。

HTTP协议

概述

  • HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web)服务器传输超文本到本地浏览器的传送协议。
  • HTTP属于应用层协议,基于TCP/IP通信协议来传递数据

特点

  • 灵活
    • HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
  • 无连接
    • 无连接的含义是通信双方在交换HTTP报文之前不需要建立HTTP连接
  • 无状态
    • 无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时应答较快。
  • 支持B/S和C/S模式
  • 默认端口80

HTTP工作原理

HTTP协议定义Web客户端如何从Web服务器请求Web页面,以及服务器如何把Web页面传送给客户端。

  • 客户端向服务器发送一个请求报文,请求报文包含请求的方法、URL、协议版本、请求头部和请求数据。
  • 服务器以一个状态行作为响应,响应的内容包括协议的版本、成功或者错误代码、服务器信息、响应头部和响应数据。

HTTP 请求/响应的步骤

  • 客户端连接到Web服务器
    一个HTTP客户端,通常是浏览器,与Web服务器的HTTP端口(默认为80)建立一个TCP套接字连接。例如,http://www.oakcms。
  • 发送HTTP请求
    通过TCP套接字,客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求数据4部分组成。
  • 服务器接受请求并返回HTTP响应
    Web服务器解析请求,定位请求资源。服务器将资源复本写到TCP套接字,由客户端读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。
  • 释放连接TCP连接
    若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求;
  • 客户端浏览器解析HTML内容
    客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码。然后解析每一个响应头,响应头告知以下为若干字节的HTML文档和文档的字符集。客户端浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并在浏览器窗口中显示。

HTTP和HTTPS的区别

  • https协议需要到CA申请证书,一般免费证书较少,因而需要一定费用。
  • http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl/tls加密传输协议。
  • http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
  • http的连接很简单,是无状态的;HTTPS协议是由SSL/TLS+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

SSL

  • 在发送方,SSL 接收应用层的数据(如 HTTP 或 IMAP 报文),对数据进行加密,然后把加了密的数据送往 TCP 套接字。
  • 在接收方,SSL 从 TCP 套接字读取数据,解密后把数据交给应用层。

SSL 提供以下三个功能

(1) SSL 服务器鉴别 允许用户证实服务器的身份。具有 SS L 功能的浏览器维持一个表,上面有一些可信赖的认证中心 CA (Certificate Authority)和它们的公钥。
(2) 加密的 SSL 会话 客户和服务器交互的所有数据都在发送方加密,在接收方解密。
(3) SSL 客户鉴别 允许服务器证实客户的身份。

SLL的工作过程:

  • 协商加密算法:浏览器A向服务器B发送浏览器的版本号和一些可选择的加密算法,B从中选出自己所支持的算法(如RSA),并告诉A
  • 服务器鉴别:服务器B向浏览器A发送包含其RSA公钥的数字证书,A使用该证书的认证机构CA公开发布的RSA公钥进行验证
  • 会话秘钥计算:由浏览器A随机产生一个秘密数.用服务器B的RSA公钥进行加密后发送给B,双方根据协商的算法产生产生共享的对称会话秘钥
  • 安全数据传输:双方用会话密钥加密和解密它们之间传输的数据并验证其完整性

https的具体实现,怎么确保安全性

HTTPS:非对称加密算法(公钥和私钥)交换对称密钥+数字证书验证身份(验证公钥是否是伪造的)+利用对称

https包括非对称加密和对称加密两个阶段,在客户端与服务器建立连接的时候使用非对称加密,连接建立以后使用的是对称加密。

首先进行https请求的前提条件是首先服务器拥有数字证书签发机构(CA)颁发的数字证书,一般为收费

HTTP加密过程:

  • 1、服务器将携带的公钥向数字证书机构申请证书。
  • 2、数字证书机构用自己的私钥对公钥签名颁发证书,并返回给服务器。
  • 3、服务器将申请携带公钥的证书分发给客服端。
  • 4、客户端验证证书,证书机构通过验证,或者用户接受不受信任的证书(非权威机构颁发的证书)。获取到公钥。到这一步,在证书保证下服务器拥有私钥,客户端拥有公钥,可进行非对称性加密。
  • 5、使用公钥加密报文发送给服务器,其中携带随机串。其中的随机串用户传输数据时进行对称加密
  • 6、服务器使用私钥解密。获取报文信息及随机串。
  • 7、解密后服务器发送握手消息给客户端。
  • 8、客户端接受握手消息,握手结束,双方确定加密算法(使用随机串确定的对称性加密),开始传输。

客户端的对称加密密钥其实是三个随机数的哈希(1. 客户端第一次给服务端发送请求时附带的随机数 2. 服务器返回时的随机数 3. 客户端收到返回时的随机数)

浏览器如何验证HTTPS证书的合法性?

简单来说是验证两个问题:
1、证书是否是信任的有效证书。所谓信任:浏览器内置了信任的根证书,就是看看web服务器的证书是不是这些信任根发的或者信任根的二级证书机构颁发的。所谓有效,就是看看web服务器证书是否在有效期,是否被吊销了。
2、对方是不是上述证书的合法持有者。简单来说证明对方是否持有证书的对应私钥。验证方法两种,一种是对方签个名,我用证书验证签名;另外一种是用证书做个信封,看对方是否能解开。

以上的所有验证,除了验证证书是否吊销需要和CA关联,其他都可以自己完成。验证正式是否吊销可以采用黑名单方式或者OCSP方式。黑名单就是定期从CA下载一个名单列表,里面有吊销的证书序列号,自己在本地比对一下就行。优点是效率高。缺点是不实时。OCSP是实时连接CA去验证,优点是实时,缺点是效率不高。

运输层安全协议及SSL工作过程

SSL 安全套接字层协议

TLS 运输层安全协议,在SSL的基础上设计

  • SSL工作过程
    • 协商加密算法
      • 浏览器A向服务器B发送SSL版本,及自身支持的加密组件(包括加密算法及密钥长度等)
      • B从中选择自身支持的加密组件和SSL版本,发送给A
    • 服务器鉴别
      • B向A发送包含公开密钥的数字证书
      • A对数字证书进行鉴别,获取B的公钥
    • 会话密钥计算
      • A随机产生秘密数,将秘密数通过B的公钥发送给B,之后A通过协商的加密算法产生会话密钥
      • B接收到秘密数后,通过B的私钥将其解密得到秘密数,然后根据协商加密算法产生会话密钥
    • 安全数据传输
      • 双方会互相发送一次数据,用会话密钥加密和解密他们之间传达的数据并验证其完整性
    • 通信
      • 上述验证通过后,才继续进行http通信

HTTPS必须在每次请求中都要先在SSL/TLS层进行握手传输密钥吗?

显然每次请求都经历一次密钥传输过程非常耗时,那怎么达到只传输一次呢?用session就行。

  • 服务器会为每个浏览器(或客户端软件)维护一个session ID,在TSL握手阶段传给浏览器,浏览器生成好密钥传给服务器后,服务器会把该密钥存到相应的session ID下
  • 之后浏览器每次请求都会携带session ID,服务器会根据session ID找到相应的密钥并进行解密加密操作,这样就不必要每次重新制作、传输密钥了!

HTTP2

  • 新的二进制格式(Binary Format)
    • HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。
  • 多路复用(MultiPlexing)
    • 即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。
    • pipelining在接收response返回时,必须依顺序接收,如果前一个请求遇到了阻塞,后面的请求即使已经处理完毕了,仍然需要等待阻塞的请求处理完毕。这种情况就如图中第三种,第一个请求阻塞后,后面的请求都需要等待,这也就是队头阻塞
  • header压缩
    • 对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小
  • 服务端推送
    • 我的网页有一个sytle.css的请求,在客户端收到sytle.css数据的同时,服务端会将sytle.js的文件推送给客户端,当客户端再次尝试获取sytle.js时就可以直接从缓存中获取到,不用再发请求了

HTTP/1. 一次请求-响应,建立一个连接,用完关闭;每一个请求都要建立一个连接;

HTTP/1.1 非流水线解决方式为,若干个请求排队串行化单线程处理,后面的请求等待前面请求的返回才能获得执行机会,一旦有某请求超时等,后续请求只能被阻塞,毫无办法,也就是人们常说的线头阻塞;

HTTP/2多个请求可同时在一个连接上并行执行。某个请求任务耗时严重,不会影响到其它连接的正常执行;
具体如图:

Token

参考:https://blog.csdn/qq_40884473/article/details/78442377

Token是在客户端频繁向服务端请求数据,服务端频繁的去数据库查询用户名和密码并进行对比,判断用户名和密码正确与否,并作出相应提示,在这样的场景下,Token便应运而生

Token是服务端生成的一串字符串,也就是令牌,最大的特点就是随机性,不可预测

Token一般用在两个地方:

  • 1)防止表单重复提交、
  • 2)anti csrf攻击(跨站点请求伪造)

token 的身份验证流程:

  • 1.客户端使用用户名跟密码请求登录
  • 2.服务端收到请求,去验证用户名与密码
  • 3.验证成功后,服务端会签发一个 token 并把这个 token 发送给客户端
  • 4.客户端收到 token 以后,会把它存储起来,比如放在 cookie 里或者 localStorage 里
    客户端每次向服务端请求资源的时候需要带着服务端签发的 token
  • 5.服务端收到请求,然后去验证客户端请求里面带着的 token ,如果验证成功,就向客户端返回请求的数据

注意:每一次请求都需要携带 token,需要把 token 放到 HTTP 的 Header 里
基于 token 的用户认证是一种服务端无状态的认证方式,服务端不用存放 token 数据。用解析 token 的计算时间换取 session 的存储空间,从而减轻服务器的压力,减少频繁的查询数据库

实施 Token 验证的方法挺多的,还有一些标准方法,比如 JWT,读作:jot ,表示:JSON Web Tokens 。JWT 标准的 Token 有三个部分:

  • header
  • payload
  • signature

Web安全

Token,我们称之为“令牌”,其最大的特点就是随机性,不可预测。一般黑客或软件无法猜测出来。那么,Token 有什么作用?又是什么原理呢?

Token 一般用在两个地方:

防止表单重复提交;
Anti CSRF 攻击(跨站点请求伪造)。

两者在原理上都是通过 session token 来实现的。当客户端请求页面时,服务器会生成一个随机数 Token,并且将 Token 放置到 session 当中,然后将 Token 发给客户端(一般通过构造 hidden 表单)。下次客户端提交请求时,Token 会随着表单一起提交到服务器端。

然后,如果应用于“Anti CSRF攻击”,则服务器端会对 Token 值进行验证,判断是否和session中的Token值相等,若相等,则可以证明请求有效,不是伪造的。不过,如果应用于“防止表单重复提交”,服务器端第一次验证相同过后,会将 session 中的 Token 值更新下,若用户重复提交,第二次的验证判断将失败,因为用户提交的表单中的 Token 没变,但服务器端 session 中 Token 已经改变了。

上面的 session 应用相对安全,但也叫繁琐,同时当多页面多请求时,必须采用多 Token 同时生成的方法,这样占用更多资源,执行效率会降低。因此,也可用 cookie 存储验证信息的方法来代替 session Token。比如,应对“重复提交”时,当第一次提交后便把已经提交的信息写到 cookie 中,当第二次提交时,由于 cookie 已经有提交记录,因此第二次提交会失败。不过,cookie 存储有个致命弱点,如果 cookie 被劫持(XSS 攻击很容易得到用户 cookie),那么又一次 game over,黑客将直接实现 CSRF 攻击。所以,安全和高效相对的,具体问题具体分析吧!

此外,要避免“加 token 但不进行校验”的情况,在 session 中增加了 token,但服务端没有对 token 进行验证,这样根本起不到防范的作用。还需注意的是,对数据库有改动的增、删、改操作,需要加 token 验证,对于查询操作,一定不要加 token,防止攻击者通过查询操作获取 token 进行 CSRF攻击。但并不是这样攻击者就无法获得 token,只是增大攻击成本而已。

cookie和session

HTTP协议作为无状态协议,对于HTTP协议而言,无状态指每次request请求之前是相互独立的,当前请求并不会记录它的上一次请求信息,如何将上下文请求进行关联呢?客户端(不同的浏览器)记录用户的状态通过cookie,服务器端(不同的网站)记录用户的状态通过session。

cookie

  • 客户端请求服务器端,服务器端产生cookie响应头,随响应报文发送给客户端,客户端将cookie文本保存起来
  • 下次客户端再次请求服务端时,会产生cookie请求头,将之前服务器发送的cookie信息,再发送给服务器,服务器就可以根据cookie信息跟踪客户端的状态。

Cookie总是保存在客户端中,按在客户端中的存储位置,可分为内存Cookie和硬盘Cookie,它是服务器端存放在本地机器中的数据,随每一个请求发送给服务器,由于Cookie在客户端,所以可以编辑伪造,不是十分安全。

  • 非持久cookie
    • 内存Cookie由浏览器维护,保存在内存中,浏览器关闭后就消失了,其存在时间是短暂的。
  • 持久cookie
    • 硬盘Cookie保存在硬盘里,有一个过期时间(客户端cookie设置的时间),除非用户手工清理或到了过期时间,硬盘Cookie不会被删除,其存在时间是长期的。

session

工作流程:

  • 当用户第一次访问站点时,服务器端为用户创建一个sessionID,这就是针对这个用户的唯一标识,每一个访问的用户都会得到一个自己独有的session ID,这个session ID会存放在响应头里的cookie中,之后发送给客户端。这样客户端就会拥有一个该站点给他的session ID。
  • 当用户第二次访问该站点时,浏览器会带着本地存放的cookie(里面存有上次得到的session ID)随着请求一起发送到服务器,服务端接到请求后会检测是否有session ID,如果有就会找到响应的session文件,把其中的信息读取出来;如果没有就跟第一次一样再创建个新的。

session是存放在服务器里的,所以session 里的东西不断增加会增加服务器的负担,我们会把一些重要的东西放在session里,不太重要的放在客户端cookie里

  • session失效

    • 服务器(非正常)关闭时
    • session过期/失效(默认30分钟)
      • 问题:时间的起算点 从何时开始计算30分钟?从不操作服务器端的资源开始计时(例如:当你访问淘宝页面时,点开页面不动,第29分钟再动一下页面,就得重新计时30分钟;当过了30分钟,就失效了。)
    • 手动销毁session
  • sessionID的传递方式

    • 通过cookie传递
    • 当cookie禁用后,可以通过url传递
  • 不同场景下的session

    • 当在同一个浏览器中同时打开多个标签,发送同一个请求或不同的请求,仍是同一个session;
    • 当不在同一个窗口中打开相同的浏览器时(打开多个相同的浏览器),发送请求,仍是同一个session;
    • 当使用不同的浏览器时,发送请求,即使发送相同的请求,是不同的session;
    • 当把当前某个浏览器的窗口全关闭,再打开,发起相同的请求时,是不同的session。

区别

  • cookie数据存放在客户的浏览器上,session数据放在服务器上。
  • cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session。
  • session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。
  • 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
  • 可以考虑将登陆信息等重要信息存放为session,其他信息如果需要保留,可以放在cookie中。

浏览器禁用cookie后,如何使用session?

sessionid是存储在cookie中的,解决方案如下:

  • Session URL重写,保证在客户端禁用或不支持COOKIE时,仍然可以使用Session

  • session机制。session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。

  • 当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否已包含了一个session标识(称为session id),如果已包含则说明以前已经为此客户端创建过session,服务器就按照session id把这个session检索出来使用(检索不到,会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个session id将被在本次响应中返回给客户端保存。 保存这个session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于 SEEESIONID。但cookie可以被人为的禁止,则必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。

经常被使用的一种技术叫做URL重写,就是把session id直接附加在URL路径的后面。
还有一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。

比如:

<form name="testform" action="/xxx"> <input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764″> <input type="text"> </form>

URL重写:

http://www.test/test;jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764

HTTP持久连接与管线化

HTTP协议首先要和服务器建立TCP连接,这需要三次握手。

  • 请求一个万维网文档的时间

    • 当建立TCP连接的三次握手前两次完成后,即经过一个RTT时间,万维网客户就把HTTP请求报文,作为建立TCP连接的三次握手中的第三次的数据,发送给万维网服务器,服务器收到HTTP请求后,把请求的文档作为响应报文返回给客户。
    • 文档传输时间+2*RTT
  • HTTP1.0非持久连接的缺点

    • 每请求一个文档,需要两倍RTT的开销。服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接,然后重新建立连接发出请求
  • HTTP1.1持久连接

    • 万维网服务器在发送响应后仍然在一段时间内保持这段连接,可以使得同一用户继续在该连接上传送后续请求和响应报文
  • 持久连接的两种工作方式

    • 非流水线方式:客户在收到前一个响应后才能发出下一个请求。服务器在发送一个对象后,TCP连接处于空闲状态,浪费服务器资源。

    • 流水线方式:不用等待响应,直接发送下一个请求,但接收的时候必须按照顺序接收,如果有一个请求阻塞,则接收会全部阻塞

      • 默认情况下,HTTP 请求是按顺序发出的,下一个请求只有在当前请求收到响应之后才会被发出。由于会受到网络延迟和带宽的限制,在下一个请求被发送到服务器之前,可能需要等待很长时间。
      • 流水线是在同一条长连接上发出连续的请求,而不用等待响应返回,这样可以避免连接延迟

什么是TCP粘包问题

[什么是TCP粘包?怎么解决这个问题] (https://blog.csdn/weixin_41047704/article/details/85340311 )

TCP粘包就是指发送方发送的若干包数据到达接收方时粘成了一包,从接收缓冲区来看,后一包数据的头紧接着前一包数据的尾,出现粘包的原因是多方面的,可能是来自发送方,也可能是来自接收方。

发送端为了将多个发往接收端的包,更加高效的的发给接收端,于是采用了优化算法(Nagle算法),将多次间隔较小、数据量较小的数据,合并成一个数据量大的数据块,然后进行封包。那么这样一来,接收端就必须使用高效科学的拆包机制来分辨这些数据。

造成TCP粘包的原因

  • 发送方原因

    TCP默认使用Nagle算法(主要作用:减少网络中报文段的数量),而Nagle算法主要做两件事:

    • 只有上一个分组得到确认,才会发送下一个分组
    • 收集多个小分组,在一个确认到来时一起发送
  • 接收方原因

    TCP接收到数据包时,并不会马上交到应用层进行处理,或者说应用层并不会立即处理。实际上,TCP将接收到的数据包保存在接收缓存里,然后应用程序主动从缓存读取收到的分组。这样一来,如果TCP接收数据包到缓存的速度大于应用程序从缓存中读取数据包的速度,多个包就会被缓存,应用程序就有可能读取到多个首尾相接粘到一起的包

粘包、拆包发生原因
发生TCP粘包或拆包有很多原因,现列出常见的几点:
1、要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包。
2、待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。
3、要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包。
4、接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包。

如何处理粘包现象?

  • 对于发送方造成的粘包问题,可以通过关闭Nagle算法来解决,使用TCP_NODELAY选项来关闭算法

  • 只能在应用层数据协议上,加以控制。通常在制定传输数据时,可以使用如下方法:

  1. 使用带消息头的协议、消息头存储消息开始标识及消息长度信息,服务端获取消息头的时候解析出消息长度,然后向后读取该长度的内容。
  2. 设置定长消息,服务端每次读取既定长度的内容作为一条完整消息。
  3. 设置消息边界,服务端从网络流中按消息编辑分离出消息内容。

TCP为了保证可靠传输并减少额外的开销(每次发包都要验证),采用了基于流的传输,基于流的传输不认为消息是一条一条的

保护消息边界:指传输协议把数据当做一条独立的消息在网上传输,接收端一次只能接受一条独立的消息

UDP则是面向消息传输的,是有保护消息边界的,接收方一次只接受一条独立的信息,所以不存在粘包问题

TCP/IP的粘包与避免介绍一下

因为TCP为了减少额外开销,采取的是流式传输,所以接收端在一次接收的时候有可能一次接收多个包。而TCP粘包就是发送方的若干个数据包到达接收方的时候粘成了一个包。多个包首尾相接,无法区分。

导致TCP粘包的原因有三方面:

  • 发送端等待缓冲区满才进行发送,造成粘包
  • 接收方来不及接收缓冲区内的数据,造成粘包
  • 由于TCP协议在发送较小的数据包的时候,会将几个包合成一个包后发送

避免粘包的措施:

  • 通过编程,强制使TCP发生数据传送,不必等到缓冲区满
  • 优化接收方接收数据的过程,使其来得及接收数据包,包括提高接收进程优先级等
  • 设置固定长度的报文或者设置报文头部指示报文的长度。

TCP的封包和拆包

因为TCP是无边界的流传输,所以需要对TCP进行封包和拆包,确保发送和接收的数据不粘连。

  • 封包:封包就是在发送数据报的时候为每个TCP数据包加上一个包头,将数据报分为包头和包体两个部分。包头是一个固定长度的结构体,里面包含该数据包的总长度。
  • 拆包:接收方在接收到报文后提取包头中的长度信息进行截取。

HTTP断点续传

要实现断点续传的功能,通常都需要客户端记录下当前的下载进度,并在需要续传的时候通知服务端本次需要下载的内容片段。

HTTP1.1协议(RFC2616)中定义了断点续传相关的HTTP头 Range和Content-Range字段,一个最简单的断点续传实现大概如下:

  • 客户端下载一个1024K的文件,已经下载了其中512K

  • 网络中断,客户端请求续传,因此需要在HTTP头中申明本次需要续传的片段:Range:bytes=512000-,这个头通知服务端从文件的512K位置开始传输文件

  • 服务端收到断点续传请求,从文件的512K位置开始传输,并且在HTTP头中增加:Content-Range:bytes 512000-/1024000,并且此时服务端返回的HTTP状态码应该是206,而不是200。

IP/TCP/UDP分片

数据发送时,将数据从应用层->传输层->网络层->数据链路层,其中传输层是TCP和UDP,网络层是IP协议。

  • MTU以太网帧的长度为1500字节,所能接收的传输层数据段最大为 1480 个字节(以太网帧中的数据包括 IP 协议的报头信息,IP 协议的报头信息为 20 字节)
  • 在计算 MSS (网络传输数据最大值)的时候,用 MTU 减去网络层报头长度以及传输层报头长度即可。
  • UDP
    • 一旦 UDP 携带的数据超过了 1472 (MTU - IP报头 - UDP报头 = 1500 - 20 - 8),那么在 IP 层就会对该数据分片,一旦分片就意味着增加了 UDP 传输丢包的可能性。 由于 UDP 协议传输本身就不负责可靠性,再加上分片,那么丢包的可能性就大大增加

短连接与长连接

当浏览器访问一个包含多张图片的 HTML 页面时,除了请求访问 HTML 页面资源,还会请求图片资源。如果每进行一次 HTTP 通信就要新建一个 TCP 连接,那么开销会很大。

长连接只需要建立一次 TCP 连接就能进行多次 HTTP 通信。

从 HTTP/1.1 开始默认是长连接(持久连接)的,如果要断开连接,需要由客户端或者服务器端提出断开,使用 Connection : close;
在 HTTP/1.1 之前默认是短连接的,如果需要使用长连接,则使用 Connection : Keep-Alive。

对称密码和公钥密码体制

  • 对称加密:加密和解密使用的密钥是同一个

    • 优点:计算量小,算法速度快,加密效率高 缺点:密钥容易泄漏。不同的会话需要不同的密钥,管理起来很费劲
    • 常用算法:DES,3DES,IDEA,CR4,CR5,CR6,AES
  • 公钥密码体制:加密密码和解密密码不同,需要公钥和私钥,公钥用来加密,私钥用来解密

    • 在公钥密码体制中,加密密钥(即公钥) PK 是公开信息,而解密密钥(即私钥或秘钥) SK 是需要保密的。

    • 加密算法 E 和解密算法 D 也都是公开的。虽然秘钥 SK 是由公钥 PK 决定的,但却不能根据 PK 计算出 SK。

    • 优点:安全,不怕泄漏 缺点:速度慢
    • 常用算法:RSA,ECC,DSA

数据加密标准 DES 属于常规密钥密码体制,是一种分组密码。

  • 在加密前,先对整个明文进行分组。每一个组长为 64 位。
  • 然后对每一个 64 位 二进制数据进行加密处理,产生一组 64 位密文数据。
  • 最后将各组密文串接起来,即得出整个的密文。
  • 使用的密钥为 64 位(实际密钥长度为 56 位,有 8 位用于奇偶校验)。

DES 的保密性仅取决于对密钥的保密,而算法是公开的

非对称加密的缺点:

  • 非对称加密时需要使用到接收方的公匙对消息进行加密,但是公匙不是保密的,任何人都可以拿到,中间人也可以。那么中间人可以做两件事,第一件是中间人可以在客户端与服务器交换公匙的时候,将客户端的公匙替换成自己的。这样服务器拿到的公匙将不是客户端的,而是中间人的。服务器也无法判断公匙来源的正确性。第二件是中间人可以不替换公匙,但是他可以截获客户端发来的消息,然后篡改,然后用服务器的公匙加密再发往服务器,服务器将收到错误的消息。

为了应对上面非对称加密带来的问题,我们就引入了数字签名

数字签名和数字证书

数字签名必须保证以下三点:

  • 报文鉴别——接收者能够核实发送者对报文的签名;

  • 报文的完整性——发送者事后不能抵赖对报文的签名;

  • 不可否认——接收者不能伪造对报文的签名。

    现在已有多种实现各种数字签名的方法。但采用公钥算法更容易实现

使用公钥密码加密的一般流程:通过A的公钥对报文加密,发送给B,然后B拿A的私钥进行解密,得到报文.
注意:并不是每次传输报文的时候都要加数字签名,数字签名一般用于数字证书的验证,这样的话浏览器内置的CA拥有服务端的公钥和私钥。

  • 数字签名

    • 普通数字签名(能核实发送者,但无法保证报文完整性)

      • A通过A的私钥对报文进行加密,将其附在报文的后面,发送给B,然后B拿A的公钥对附加信息进行解密的过程,为数字签名
      • 上述过程中仅仅实现了数字签名,但并没有对实际报文进行加密。实际操作时,可以通过A–>A私钥(数字签名)–>B公钥(报文加密)–>B私钥(报文解密)–>A公钥(验证数字签名)
    • 密码散列函数

      • 使用密码散列函数对报文进行与运算得到hash值,简称摘要
      • 密码散列函数有MD5和安全散列算法SHA
    • 报文摘要数字签名(核实发送者,保证报文完整性)
      对报文本身加密可能是个耗时过程,比如这封Email足够大,那么私钥加密整个文件以及拿到文件后的解密无疑是巨大的开销

      • A先对这封Email执行哈希运算得到hash值简称“摘要”,取名h1
      • 然后用自己私钥对摘要加密,生成的东西叫“数字签名”
      • 把数字签名加在Email正文后面,一起发送给B
      • 防止邮件被窃听你可以用继续B公钥加密
      • B收到邮件后使用B私钥对报文解密,用A的公钥对数字签名解密,成功则代表Email确实来自A,失败说明有人冒充
      • B对邮件正文执行哈希运算得到hash值,取名h2
      • B会对比数字签名的hash值h1和自己运算得到的h2,一致则说明邮件未被篡改。
    • 数字签名的作用

      • 确认核实发送者
      • 保证报文的完整性
      • 一般用于验证数字证书
  • 数字证书
    明文和数字签名共同组成了数字证书,这样一份数字证书就可以颁发给网站了,由认证中心(CA)或者认证中心的下级认证中心颁发。通俗来说,A确认收到的公钥真的是B的公钥,而不是别人伪造的

    • 制作数字签名
      • CA拥有非对称加密的私钥和公钥。
      • CA对证书明文信息进行hash。
      • 对hash后的值用私钥加密,得到数字签名
      • 明文和数字签名共同组成了数字证书
    • 数字证书验证过程
      • 拿到证书,得到明文T,数字签名S。
      • 用CA机构的公钥对S解密,得到S’。(由于是浏览器信任的机构,浏览器保有它的公钥,操作系统、浏览器本身会预装一些它们信任的根证书,如果其中有该CA机构的根证书,那就可以拿到它对应的可信公钥)
      • 用证书里说明的hash算法对明文T进行hash得到T’。
      • 比较S’是否等于T’,等于则表明证书可信。

消息摘要算法,MD5算法,为什么MD5是不可逆的,有什么办法可以加强消息摘要算法的安全性让它不那么容易被破解呢?

  • 消息摘要算法有MD家族(MD2,MD4,MD5),SHA家族(SHA-1,SHA-256)和CRC家族(CRC8,CRC16,CRC32)等等
  • MD5算法介绍:
    MD5以512位分组来处理输入的信息,且每一分组又被划分为若干个小分组(16个32位子分组),经过一些列的处理后,算法输出由四个散列值(32位分组组成的128位散列值。)
    • MD5首先将输入的信息分成若干个512字节长度的分组,如果不够就填充1和若干个0。
    • 对每个512字节的分组进行循环运算。使用四个幻数对第一个分组的数据进行四轮变换,得到四个变量。
    • 接下来对其中三个使用线性函数进行计算,与剩下一个相加,并赋值给其中某个变量,得到新的四个变量,重复16次这个过程,得到的四个变量作为幻数,与下一个分组进行相似的计算。
    • 遍历所有分组后得到的四个变量即为结果。

详见:https://blog.csdn/weixin_39640298/article/details/84555814

  • 为什么不可逆:因为MD5在进行消息摘要的过程中,数据与原始数据相比发生了丢失,所以不能由结果进行恢复。
  • 加强安全性:加盐(加随机数)

Syn Flood 攻击

SYN Flood攻击指的是一种常见的拒绝服务攻击。这种攻击可能对主机实施,阻止主机处理连接的工作。这里解释一下, TCP是传输控制协议,是大多数数据在互联网上传输的主要手段。为了使用TCP协议打开互联网上的一台主机的连接,在客户机和服务器之间将产生“三次握手"

SYN Flood攻击是一种利用TCP协议缺陷,发送大量伪造的TCP连接请求,常用假冒的IP或IP号段发来海量的请求连接的第一个握手包(SYN包),被攻击服务器回应第二个握手包(SYN+ ACK包),因为对方是假冒IP对方永远收不到包且不会回应第三个握手包。导致被攻击服务器保持大量SYN RECV状态的“半连接”,并且会重试默认5次回应第二个握手包,塞满TCP等待连接队列,资源耗尽(CPU满负荷或内存不足) ,让正常的业务请求连接不进来。

当开放了一个TCP端口后,该端口就处于Listening状态,不停地监视发到该端口的SYN报文,一旦接收到Client发来的SYN报文,就需要为该请求分配一个TCB(Transmission Control Block),通常一个TCB至少需要280个字节,在某些操作系统中TCB甚至需要1300个字节,并返回一个SYNACK报文,立即转为SYN-RECEIVED即半开连接状态,而某些操作系统在SOCKT的实现上最多可开启512个半开连接(如Linux2.4.20 内核)。这种过程如下图所示:

从以上过程可以看到,如果恶意的向某个服务器端口发送大量的SYN包,则可以使服务器打开大量的半开连接,分配TCB,从而消耗大量的服务器资源,同时也使得正常的连接请求无法被相应。而攻击发起方的资源消耗相比较可忽略不计。

syn flood防御方法:

SYN Cache技术:

这种技术是在收到SYN数据报文时不急于去分配TCB,而是先回应一个SYN ACK报文,并在一个专用HASH表(Cache)中保存这种半开连接信息,直到收到正确的回应ACK报文再分配TCB。在FreeBSD系统中这种Cache每个半开连接只需使用160字节,远小于TCB所需的736个字节。在发送的SYN ACK中需要使用一个己方的Sequence Number,这个数字不能被对方猜到,否则对于某些稍微智能一点的SYNFlood攻击软件来说,它们在发送SYN报文后会发送一个ACK报文,如果己方的Sequence Number被对方猜测到,则会被其建立起真正的连接。因此一般采用一些加密算法生成难于预测的Sequence Number。

syn cookie/proxy

syn cookie 它的防御对象是syn flood,类别是:DOS攻击方式的防范手段,防范原理:修改TCP服务器端的三次握手协议

syn cookie 是对TCP服务器端的三次握手协议做了一些修改,专门用来防范SYN Flood 攻击的手段。它的原理是:在TCP服务器收到TCP syn包并返回TCP SYN+ACK包时,不分配一个专门的数据区,而是根据这个SYN包计算出一个cookie值,在收到TCP ACK包时,TCP 服务器在根据那个cookie值检查这个TCP ACK包的合法性。如果合法,再分配专门的数据区进行处理未来的TCP连接。

CSRF与XSS

  • XSS 攻击:跨站脚本攻击(Cross Site Scripting),恶意攻击者往 Web 页面里插入恶意 Script 代码,当用户浏览该页之时,嵌入其中 Web 里面的 Script 代码会被执行,从而达到恶意攻击用户的目的。

    XSS (Cross Site Scripting),即跨站脚本攻击,是一种常见于 Web 应用中的计算机安全漏洞。恶意攻击者往 Web 页面里嵌入恶意的客户端脚本,当用户浏览此网页时,脚本就会在用户的浏览器上执行,进而达到攻击者的目的。比如获取用户的 Cookie、导航到恶意网站、携带木马等

    • XSS 漏洞是由于对用户提交的数据没有经过严格的过滤处理造成的,所以防御的原则就是不相信用户输入的数据,对输入进行过滤,对输出进行编码。
  • CSRF 攻击:CSRF(Cross-site request forgery)跨站请求伪造,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与 XSS 非常不同,XSS 利用站点内的信任用户,而 CSRF 则通过伪装来自受信任用户的请求来利用受信任的网站。与 XSS 攻击相比,CSRF 攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比 XSS 更具危险性。

    CSRF攻击攻击原理及过程如下:

    1. 用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A;

    2.在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;

    1. 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;

    2. 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;

    3. 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。

CSRF是一种夹持用户在已经登陆的web应用程序上执行非本意的操作的攻击方式。相比于XSS,CSRF是利用了系统对页面浏览器的信任,XSS则利用了系统对用户的信任。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j2r05fds-1649154398330)(./pic/CSRF攻击原理图.jpg)]

可以知道构成CSRF攻击是有条件的:

  • 客户端必须一个网站并生成cookie凭证存储在浏览器中
  • 该cookie没有清除,客户端又tab一个页面进行访问别的网站

ARP欺骗

任何一台机器都可以轻松的发送ARP广播,来宣称自己的IP和自己的MAC。这样收到的机器都会在自己的ARP表格中建立一个他的ARP项,记录他的IP和MAC地址。如果这个广播是错误的其他机器也会接受。

ARP欺骗的关键所在,伪造了一个假的网关地址,并进行广播,因为局域网中的主机要进行通信的话,必经过网关,那么若被欺骗后,该主机上发送的数据就会被转发到攻击者的主机上,这时攻击者可对流量进行分析,再把数据转发给真正的网关,那么受害者的数据就会被攻击者所窃取。

ARP 攻击,对内网的PC进行攻击,使内网PC机的ARP列表混乱,导致内网某些PC机无法上网。目前路由器无法抵挡这种病毒的攻击,因为他们的攻击方式是攻击内网的PC机,只有请用户从内网的PC机下手防范。

打洞听说过吗?打洞是用什么协议实现的呢

P2P就是这样的技术,可以使得不同局域网的内网设备可以直连。P2P(peer to peer)点对点技术又称对等互联网络技术,是一种网络新技术,依赖网络中参与者的计算能力和带宽,而不是把依赖都聚集在较少的几台服务器上。

根据客户端的不同,客户端之间进行P2P传输的方法也略有不同,P2P主要有中继、逆向连接、打洞(hole punching)等技术。

中继(Relaying)

中继最可靠但也是最低效的一种P2P通信实现,其原理是通过一个有公网IP的服务器中间人对两个内网客户端的通信数据进行中继和转发,如图 1所示:

当服务端连接的客户端比较少,且网络流量不大时,效果还不错。但是如果有很多客户端连接并且网络流量很多,服务端的压力就会很大。

逆向连接(Connection reversal)

此种方法在两个端点中有一个不存在中间件(如NAT)的时候有效。例如,Client A在NAT之后而Client B拥有全局IP地址

Client A内网地址为10.0.0.1,使用TCP,端口为1234。A和Server S建立了一个连接,Server的IP地址为18.181.0.31,监听1235端口。NAT A给Client A分配了TCP端口62000,地址为NAT的公网IP地址155.99.25.11,作为Client A对外当前会话的临时IP和端口。因此Server S认为Client A就是155.99.25.11:62000。而Client B由于有公网地址,所以对Server S来说Client B就是138.76.29.7:1234。

当Client B想要主动发起对Client A的P2P连接时,需要指定目的地址及端口为155.99.25.11:62000。由于NAT工作的原理问题,NAT A会拒绝将收到的对Client A的请求转发给Client A。拒绝该请求主要有如下原因:

  1. NAT A没有映射过62000端口,NAT A不知道该请求是给谁的

  2. NAT A映射过62000端口,但是需要首先从Client A发起请求,然后才能转发应答

在直接连接Client A失败之后,Client B可以通过Server S向Client A中继一个连接请求,从而从Client A方向“逆向“地建立起Client A- Client B之间的点对点连接(因为Client A连接到了Server S)。

很多当前的P2P系统都实现了这种技术,但其局限性也是很明显的,只有当其中一方有公网IP时连接才能建立。越来越多的情况下,通信的双方都在NAT之后,因此就要用到打洞技术了

UDP打洞

对于UDP打洞,考虑如下的两张场景:

  • 两 个Client 处在两个不同的NAT

  • 两个Client 在同一个NAT

端点处于不同NAT

Client A和Client B的地址都是内网地址,且在不同的NAT后面。Client A、Client B上运行的P2P应用程序和Server S都使用了UDP端口1234,Client A和Client B分别初始化了与Server S的UDP通信

假设Client A打算与Client B直接建立一个UDP通信会话。如果Client A直接给Client B的公网地址138.76.29.7:31000发送UDP数据,NAT B很可能会无视进入的数据(除非是Full Cone NAT),Client B往Client A直接发信息也类似。

为了解决上述问题,在Client A开始给Client B的公网地址发送UDP数据的同时,Client A给Server S发送一个中继请求,要求Client B开始给Client A的公网地址发送UDP信息。Client A往Client B的输出信息会导致NAT A打开一个Client A的内网地址与Client B的外网地址之间的通讯会话,Client B往Client A亦然。当两个方向都打开会话之后,Client A和Client B就能直接通讯,而无须再通过Server S了。

UDP打洞技术有许多有用的性质。一旦一个的P2P连接建立,连接的双方都能反过来作为“引导服务器”来帮助其他中间件后的客户端进行打洞,极大减少了服务器的负载。应用程序不需要知道中间件是什么(如果有的话),因为以上的过程在没有中间件或者有多个中间件的情况下也一样能建立通信链路。

端点处于相同的NAT

如果Client A和Client B正好在同一个NAT(而且可能他们自己并不知道),Client A和Server S建立了一个UDP会话,NAT为此分配了公网端口62000,Client B同样和Server S建立会话,分配到了端口62001

假设Client A和Client B使用了上节介绍的UDP打洞技术来建立P2P通路,那么交互流程就是这样了:

  1. Client A和Client B得到由Server S观测到的对方的公网IP和端口号,然后给对方的地址发送信息

  2. 当Client A发送一个UDP数据包给Client B的公网地址,数据包最初有源IP地址和端口地址10.0.0.1:1234和目的地址155.99.25.11:62001

  3. NAT收到包后,将其转换为源155.99.25.11:62000(Client A的公网地址)和目的10.1.1.3:1234,NAT发现目的公网地址和其本身的公网地址相同,此时有两种做法:

  4. 如果NAT支持回环传输(NAT允许同一个内网的主机间相互通信),那么直接将数据发给Client B

  5. 如果NAT不支持回环传输,有可能将该数据丢弃

因为从内部到达NAT的数据会被“回送”到内网中而不是转发到外网。即便NAT支持回环传输,这种转换和转发在此情况下也是没必要的,且有可能会增加A与B的对话延时和加重NAT的负担。
解决上述问题也很简单:

  1. 当Client A和Client B最初通过Server S交换地址信息时,它们包含自身的IP地址和端口号(从自己看),同时也包含从服务器看的自己的地址和端口号

  2. Client 向对方的公网地址及内网地址同时发生数据,并使用第一个成功通信的地址作为对方地址。如果两个Client 在同一个NAT后,发送到对方内网地址的数据最有可能先到达,从而可以建立一条不经过NAT的通信链路

  3. 如果两个Client 在不同的NAT之后,发送给对方内网地址的数据包根本就到达不了对方,但仍然可以通过公网地址来建立通路。

值得一提的是,虽然这些数据包通过某种方式验证,但是在不同NAT的情况下完全有可能会导致Client A往Client B发送的信息发送到其他Client A内网网段中无关的结点上去的。

TCP打洞

TCP打洞

建立穿越NAT设备的P2P的TCP连接只比UDP复杂一点点,TCP协议的 “打洞”从协议层来看是与UDP的“打洞”过程非常相似的。尽管如此,基于TCP协议的打洞至今为止还没有被很好的理解,这也造成了的对其提供支持的NAT设备不是很多。在NAT设备支持的前提下,基于TCP的“打洞”技术实际上与基于UDP的“打洞”技术一样快捷、可靠。实际上,只要NAT设备支持的话,基于TCP的P2P技术的健壮性将比基于UDP技术的更强一些,因为TCP协议的状态机给出了一种标准的方法来精确的获取某个TCP session的生命期,而UDP协议则无法做到这一点。
套接字和TCP端口的重用

实现基于TCP协议的P2P打洞过程中,最主要的问题不是来自于TCP协议,而是来自于应用程序的API接口。这是由于标准的伯克利(Berkeley)套接字的API是围绕着构建Client /服务器程序而设计的,API允许TCP套接字通过调用connect()函数来建立向外的连接,或者通过listen()和accept函数接受来自外部的连接,但是,API不提供类似UDP那样的,同一个端口既可以向外连接,又能够接受来自外部的连接。而且更糟的是,TCP的套接字通常仅允许建立1对1的响应,即应用程序在将一个套接字绑定到本地的一个端口以后,任何试图将第二个套接字绑定到该端口的操作都会失败。

为了让TCP打洞能够顺利工作,我们需要使用一个本地的TCP端口来监听来自外部的TCP连接,同时建立多个向外的TCP连接(通过SO_REUSEADDR、SO_REUSEADDR)。
打开P2P的TCP流

假定Client A希望建立与Client B的TCP连接(Client A和Client B已经与公网上的服务器建立了TCP连接),步骤为:

  1. Client A使用其与服务器的连接向服务器发送请求,要求服务器协助其连接Client B;

  2. 服务器将Client B的公网和内网的TCP地址的二元组信息返回给A,同时,服务器将Client A的公网和内网的地址二元组也发送给Client B;

  3. Client A和Client B使用连接服务器的端口异步地发起向对方的公网、内网地址二元组的TCP连接,同时监听各自的本地TCP端口是否有外部的连接联入;

  4. Client A和Client B开始等待向外的连接是否成功,检查是否有新连接联入。如果向外的连接由于某种网络错误而失败,如:“连接被重置”或者“节点无法访问”,Client 只需要延迟一段时间(例如延迟一秒钟),然后重新发起连接即可,延迟的时间和重复连接的次数可以由应用程序编写者来确定;

  5. TCP连接建立起来以后,Client 之间应该开始鉴权操作,确保目前联入的连接就是所希望的连接。如果鉴权失败,Client 将关闭连接,并且继续等待新的连接联入。Client 通常采用“先入为主”的策略,只接受第一个通过鉴权操作的Client ,然后将进入P2P通信过程不再继续等待是否有新的连接联入。

与UDP不同的是,因为使用UDP协议的每个Client 只需要一个套接字即可完成与服务器的通信,而TCP Client 必须处理多个套接字绑定到同一个本地TCP端口的问题。现在来看实际中常见的一种情景,A与B分别位于不同的NAT设备后面,如图 3所示,并且假定图中的端口号是TCP协议的端口号,而不是UDP的端口号。图中向外的连接代表Client A和Client B向对方的内网地址二元组发起的连接,这些连接或许会失败或者无法连接到对方。如同使用UDP协议进行“打洞”操作遇到的问题一样,TCP的“打洞”操作也会遇到内网的IP与“伪”公网IP重复造成连接失败或者错误连接之类的问题。

Client 向彼此公网地址二元组发起连接的操作,会使得各自的NAT设备打开新的“洞”允许Client A与Client B的TCP数据通过。如果NAT设备支持TCP“打洞”操作的话,一个在Client 之间的基于TCP协议的流通道就会自动建立起来。如果Client A向Client B发送的第一个SYN包发到了Client B的NAT设备,而Client B在此前没有向Client A发送SYN包,Client B的NAT设备会丢弃这个包,这会引起A的“连接失败”或“无法连接”问题。而此时,由于Client A已经向Client B发送过SYN包,Client B发往Client A的SYN包将被看作是由Client A发往Client B的包的回应的一部分,所以Client B发往Client A的SYN包会顺利地通过Client A的NAT设备,到达Client A,从而建立起Client A与Client B的P2P连接。
TCP同时打开

有一种特殊的TCP P2P打洞场景:假定各终端的TCP连接启动时间比较巧合,使得他们各自发送的 SYN报文,在到达对方的NAT设备之前,对方的SYN报文都已经 穿越NAT设备,并在NAT设备上生成TCP映射关系。在这种“幸 运”的情况下,NAT设备不会拒绝SYN报文,双方的SYN报文都 能通过终端间的NAT设备,到达对方。此时,终端会发现TCP连 接同时打开,每个终端的TCP返回SYN-ACK报文,报文的SYN 部分必须与之前发送的SYN报文一样,而ACK部分告知对方到达的SYN信息。

为什么这种方式可以建立TCP连接呢?这是因为TCP三次握手中有一种特殊的场景:通信双方同时在相同端口打开连接的场景,如图 6所示:

本文标签: 计算机网络