1、OSI 七层模型及以太网协议族
2、常见车载应用层协议
车外网常见 MQTT、HTTP、FTP、DNS、DHCP
车内网常见 IPCP、SOMEIP、DOIP、DDS
3、HTTP 协议简介
HTTP 全称为 HyperText Transfer Protocol,即超文本传输协议,它是架设在 TCP (或 UDP )协议之上的应用层协议。
HTTP/2 与 HTTP/1.1 有几处关键的差异点:
- HTTP/2 是二进制协议而不是文本协议。不再可读,也不可无障碍的手动创建。
- HTTP/2 是一个多路复用协议。并行的请求能在同一个连接中处理,移除了 HTTP/1.x 中顺序和阻塞的约束。
- HTTP/2 压缩了请求头。因为请求头在一系列请求中常常是相似的,其降低了传输重复数据的成本。
- 允许服务器在客户端缓存中填充数据,通过一个叫服务器推送的机制来提前请求。
HTTP/3:
HTTP/3 有着与 HTTP 早期版本的相同语义,但在传输层部分使用 QUIC 而不是 TCP。QUIC 旨在为 HTTP 连接设计更低的延迟。类似于 HTTP/2,它是一个多路复用协议,但是 HTTP/2 通过单个 TCP 连接进行数据传输,所以在 TCP 层处理数据包丢失检测和重传会阻塞所有的数据流,而 QUIC 通过 UDP 运行多个数据流,并为每个数据流独立实现数据包丢失检测和重传,因此如果某个数据流发生错误,只会阻塞相应的数据流,其他数据流仍可正常传输。
注意:从 HTTP/2 开始,与 HTTP/1.1 存在较大差异,以下介绍的内容主要针对 HTTP/1.1
URI & URL & URN
Web 上可用的每种资源( HTML文档、图像、音频、视频片段、程序等)都由一个通用资源标识符(Uniform Resource Identifier,简称 "URI")进行标识,为了进一步定位资源所在的位置,便衍生出 URL 和 URN 两种表达方式。
简单理解:URN 作用就好像一个人的名字,URL 就像一个人的地址。换句话说:URN 确定了东西的身份,URL 提供了找到它的方式。
在开发 HTTP 相关的接口时,用的最多的是利用 URL 来表达信息,所以下面重点介绍 URL。
针对 HTTP 协议的 URL 常见定义格式如下:
scheme://host[:port]/path/…/[?query-string][#anchor]
- scheme:协议类型,如 http、https 等。
- host:HTTP 服务器的 IP 地址或者域名。
- port:HTTP 服务器的默认端口是 80,在这种情况下端口号可以省略。如果使用了别的端口,则必须显示指明。
- path:被访问资源的路径
- query-string:发送给服务器的查询参数
- anchor:锚点定位,通常此信息是不会被服务端处理的,一般是用在客户端对服务器响应的资源做进一步定位
示例:
MIME
MIME(Multipurpose Internet Mail Extensions) 是描述消息内容类型的标准,用来表示文档、文件或字节流的性质和格式。MIME 的组成结构非常简单,由类型与子类型两个字符串组成,中间用 / 分隔,即 type/subtype。
MIME 类型对大小写不敏感,但是传统写法都是小写。
常见 MIME 类型如下表所示:
type | MIME | 含义 |
text | text/plain, text/html, text/css, text/javascript | 表明资源是普通文本,理论上是人类可读的 |
image | image/gif, image/png, image/jpeg, image/bmp, image/webp, image/x-icon | 表明资源是某种图像。不包括视频,但动态图(如动态 gif)也划归于 image 类型 |
audio | audio/midi, audio/mpeg, audio/webm, audio/ogg, audio/wav | 表明资源是某种音频文件 |
video | video/webm, video/ogg | 表明资源是某种视频文件 |
application | application/octet-stream, application/pkcs12, application/xml, application/json, application/pdf, application/x-www-form-urlencoded | 表明资源是某种二进制数据 |
multipart | multipart/form-data | 由多种数据格式组成,常用于文件的上传 |
HTTP 请求报文结构
- 请求行【request-line】: 由请求方式、请求地址和 HTTP 协议版本组成
- 请求头【headers】: 消息报头,用于客户端携带附加信息,允许多个请求头存在,采用 key:value 的形式进行声明
- 空行【blank-line】: 位于请求行和请求数据之间,空行是必须的
- 请求体【body】: 非必须,通常只对 POST 请求方式有效
常用的 HTTP 请求头字段
header | 含义 |
Host | 客户端请求的域名 |
Connection | 告诉服务端,处理完本请求后,是否关闭连接 |
User-Agent | 客户端使用的浏览器或 APP 类型及版本 |
Accept | 客户端支持哪些 MIME 类型的文档 |
Accept-Encoding | 客户端支持的编码类型,如 gzip |
Accept-Language | 客户端支持的语言类型,如 zh-CN,en-US |
Referer | 指明客户端从哪个网页发起请求的,常用于防盗链 |
Cache-Control | 指定缓存机制 |
Cookie | 携带 Cookie 信息 |
HTTP 响应报文结构
- 响应行【status-line】: HTTP 协议版本、响应状态码和状态描述信息
- 响应头【headers】: 响应报头,用于服务端携带附加信息,允许多个响应头存在,采用 key:value 的形式进行声明
- 空行【blank-line】:位于响应头和响应实体之间,空行是必须的
- 响应体【body】:携带服务器返回给客户端(如浏览器)的数据
常用的 HTTP 响应头字段
header | 含义 |
Allow | 表明服务器支持哪些请求方法,如 GET,POST,HEAD 等 |
Content-Encoding | 响应内容编码方法 |
Content-Type | 响应内容属于哪种 MIME 类型 |
Content-Length | 响应内容的长度 |
Date | 当前 GMT 时间 |
Expires | 响应内容过期时间,过期后将不再缓存内容 |
Last-Modified | 文档的最后改动时间 |
Location | 告诉客户端到哪里获取文档,一般用于重定向 |
Refresh | 浏览器在多少秒后刷新文档 |
Server | 服务器名字 |
Set-Cookie | 设置和页面关联的 Cookie |
常见响应状态码
可通过响应状态码初步定位请求故障原因
status code | description | 含义 |
200 | Ok | 客户端请求成功 |
302 | Found | 请求重定向 |
400 | Bad Request | 客户端请求有语法错误,不能被服务器所理解 |
401 | Unauthorized | 请求未经授权 |
403 | Forbidden | 服务器收到请求,但拒绝提供服务 |
404 | Not Found | 请求资源不存在,eg:输入错误的URL |
405 | Method Not Allowed | 请求方式不支持 |
500 | Internal Server Error | 服务器内部发生不可预期的错误 |
502 | Bad Gateway | 服务器网关异常 |
503 | Server Unavailable | 服务器当前不能处理客户端的请求,一段时间后可能恢复正常 |
HTTP 请求方法
HTTP/1.0:定义了三种请求方法,即 GET、POST、HEAD
HTTP/1.1:新增了五种请求方法,分别为 OPTIONS、PUT、DELETE、TRACE 和 CONNECT
其中 GET 和 POST 是最常用的,其次是 HEAD 和 OPTIONS;像 PUT 和 DELETE 属于危险方法,服务器一般都会禁用;TRACE 和 CONNECT 则非常少见
GET 请求
获取 URL 指定的资源,GET 请求方法是最简单的也是最常用的。使用 GET 方法时,可以将请求参数和对应的值附加在 URI 后面,利用一个问号 (“?”) 将资源的 URI 和请求参数隔开,各个请求参数对之间使用符号 (“&”) 隔开,如 /index?username=jmlee&password=123123。
POST 请求
一般用于提交数据(如提交表单或上传文件)。表单提交使用 POST 相比 GET 安全性更高,且 GET 的 URL 有长度限制,导致携带的数据大小受限。上传大文件必须使用 POST 。
HEAD 请求
与 GET 用法相同,但没有响应体,使用场合没有 GET 多。如下载前使用 HEAD 发送请求,通过 Content-Length 响应字段来了解网络资源的大小;或通过 Last-Modified 响应字段来判断本地缓存资源是否需要更新。
OPTIONS 请求
通过 OPTIONS 方法,可以向服务器询问具体支持哪些方法、通知客户端服务器会使用什么样的方法来处理一些特殊资源。可以说这是一个探测性的方法,客户端通过该方法可以在不访问服务器上实际资源的情况下就知道处理该资源的最优方式。此请求方法常出现在跨域请求的场景中。
PUT 请求
用于向指定资源位置上传其最新内容(原来没有就上传,有就上传并覆盖原来的内容)。
DELETE 请求
请求服务器删除 URI 所标识的资源。
TRACE 请求
回显服务器收到的请求,主要用于测试或诊断,比较少见。
CONNECT 请求
开启与所请求资源之间的双向沟通通道,它可以用来创建隧道。
重点介绍下 GET 和 POST 的区别:
对比项 | GET | POST |
后退按钮/刷新 | 无影响 | 数据会被重新提交(浏览器应该告知用户数据会被重新提交) |
书签 | 可收藏为书签 | 不可收藏为书签 |
缓存 | 能被缓存 | 不能缓存 |
编码类型 | application/x-www-form-urlencoded | application/x-www-form-urlencoded or multipart/form-data |
历史 | 参数保留在浏览器历史中 | 参数不会保存在浏览器历史中 |
对数据长度的限制 | 当发送数据时,GET 方法通过 URL 添加数据,而 URL 的长度是受限制的(不同浏览器大小存在差异) | 无限制,数据会放在请求体中 |
对数据类型的限制 | 只允许 ASCII 字符 | 没有限制,允许二进制数据 |
安全性 | 与 POST 相比,GET 的安全性较差,因为所发送的数据是 URL 的一部分。 在发送密码或其他敏感信息时千万不要使用 GET | POST 相比 GET 更安全,因为参数不会被保存在浏览器历史或 web 服务器日志中 |
可见性 | 数据在 URL 中对所有人都是可见的 | 数据不会显示在 URL 中,相对安全 |
HTTP 的连接管理
在 HTTP/1.x 里有多种连接模型,分别是:短连接、长连接和 Pipeline,其中长连接模型和 Pipeline 模型是从 HTTP/1.1 开始新增的。
- 短连接模型:每次请求响应之后便关闭连接,相对性能较低。
- 长连接模型:保持连接以完成多次连续的请求,减少不断重新建立连接的时间。
- Pipeline 模型(也称流水线模型):多个连续的请求甚至都不用等待立即返回就可以被发送,这样就减少了耗费在网络延迟上的时间。
现在普遍使用的是 HTTP/1.1 的长连接模型,因为 Pipeline 模型存在一些缺陷:
1. 中间经历的代理服务器不可预知,一旦代理服务器不支持 Pipeline 模型,则整个请求链条将受限于代理服务器的性能瓶颈。
2. 正确实现 Pipeline 是比较复杂的:传输中的资源大小、多少有效的 RTT 会被用到以及有效带宽都会直接影响到 Pipeline 的性能。如果无法明确上述参数,重要的消息可能被延迟到不重要的消息后面。
3. 并不是所有的 HTTP 请求都能使用 Pipeline 模型:只有幂等方式,比如 GET、HEAD、PUT 和 DELETE 能够被安全地重试。如果有故障发生时,Pipeline 的内容要能被轻易的重试。
4. Pipeline 受制于队头阻塞(HOL)问题
HTTP 交互流程
一次完整的 HTTP 请求大致流程如下:
1、客户端和服务端建立连接
2、客户端发送请求
3、服务端接收请求,将处理结果响应给客户端
4、关闭客户端和服务端的连接(HTTP1.1后不会立即关闭连接)
存粹的 HTTP 协议都是基于请求-响应模型进行开发的,通常都由 Client 端主动发起请求,Server 端回复响应
示例:一个 HTTP GET 请求报文格式如下
GET http://developer.mozilla.org/en-US/docs/Web/HTTP/Messages HTTP/1.1
Host: developer.mozilla.org
Accept-Language: fr
4、SOMEIP 与 HTTP 的选择
SOA (Service Oriented Architecture) 是什么?
SOA 其实是一种软件设计理念,所有的功能模块都是建立在服务之上,而服务可简单理解为一系列软件接口的集合,如下定义:
"AirCondition-Service": [ // 空调服务
"getTempture": { 接口定义 }, // 获取空调温度
"setTempture": { 接口定义 }, // 设置空调温度
...
]
"Power-Service": [ // 动力服务
"getSpeed": { 接口定义 }, // 获取车速
"getTorque": { 接口定义 }, // 获取扭矩
...
]
"GNSS-Service": [ // 位置服务
"getCurrentPosition": { 接口定义 }, // 获取位置信息
"getRealTime": { 接口定义 },
...
]
我们可以将整车所有的 ECU 看成是一个整体,此时每个 ECU 即为一个个分布式模块,每个服务独立部署(持续集成,灰度发布,热更新)。
当服务划分的粒度足够小,也被称为微服务,即每个服务所承担的功能足够单一,符合软件开发高内聚低耦合的特点
为了实现 SOA,就不得不提 RPC,那 RPC (Remote Procedure Call) 是什么?
直译过来叫远程过程调用,也就是某个请求方(调用者)在本地调用某一软件接口,所调用的接口执行完毕之后返回结果给请求方,在请求方看来整个过程看似和本地方法调用一样。为了实现远程过程调用,通常需实现如下软件架构。
RPC 一定是要基于以太网吗?
答案是否定的,我们知道传统的 CAN 是基于信号的形式进行通讯交互的,但只要我们在信号的基础上新增一个序列化层,完全可以将其改造成基于服务的形式,只是 CAN 承载的数据负载有限,在中间添加一个序列化层对于上层应用而言成效甚微,用户还是无法随意定义数据负载的内容。举例说明 :
如下信号结构1:
{
char[2] name;
int age;
bool gender;
}
经过序列化层处理之后排列到CAN数据场后的结果如下(理想情况下),总共占用7个字节,还剩1个字节用于存放数据。
字段名 | name | age | gender |
占用字节数 | 2byte | 4byte | 1byte |
一旦将其改成信号结构2,序列化层处理之后一下子就把数据场用完了,显然很不灵活,即便采用 CANFD(数据场64Byte)等协议,改善也不是很明显。
{
char[8] name;
int age;
bool gender;
}
字段名 | name | age | gender |
占用字节数 | 8byte | 无法承载 | 无法承载 |
因此 RPC 需要建立在数据场能够承载足够的内容且传输速率高的通讯协议,环顾现有的通讯技术,显然以太网是比较好的选择,其数据场可承载较大的数据(通常是 1500Byte - 协议头长度),且传输速率高,支持点对点通信,所以现在的 RPC 通常都是建立以太网之上。
我们知道在车载领域,用的比较多的应用层协议有 SOMEIP 和 HTTP,那到底该如何选择 SOMEIP 和 HTTP 呢?
SOMEIP 与 HTTP 对比:
对比项 | HTTP 1.1 | SOMEIP |
序列化方式 | 文本传输(效率较低) | 二进制传输 |
支持长连接 | 是 | 是 |
支持服务发现 | 否 | 是 |
支持订阅或消息推送 | 否 | 是 |
资源消耗 | 相对较大 | 适中 |
传输数据量 | 大 | 小 |
传输层协议 | TCP | UDP/TCP |
适用范围 | 各行各业 | 车载领域 |
总结:对于车内网的控制器,可采用轻量化的 SOMEIP 协议,对于支持上网的控制器,要求即支持 SOMEIP,也支持 HTTP。HTTP 更多针对请求响应的场景,常以 Restful 的形式表示接口含义,SOMEIP 不仅支持请求响应,还支持服务端周期性通知,更适合一些实时性要求较高的场景。