开发基于网络的程序时,有许多因素需要考虑,以确保你的应用程序是高效、安全、可伸缩和用户友好的。但是今天这篇文章更加关注的是 OSI 模型中的应用层协议和运输层的协议,基于这些层的程序开发更加关注什么?如果作为一名应用开发者我们最多接触到的网络层面上的应用协议和运输协议;应用的概念更加面向用户,强调的是提供某种服务或功能,可以是桌面应用、移动应用、Web 应用等,这里围绕的是应用开发如何对网络协议选型,因为应用开发是在操作系统用户态上的开发,对于内核的可编程操作是不允许的,所以本篇文章更加关注的是基于 TCP/UDP 之上的协议选型时要考虑的问题。
TCP 和 UDP
TCP 和 UDP 都是运输层提供两套协议,提供系统内核的 API 可以使用它进行运输数据包达到另外一台主机上,市面上很多的远程调用框架例如 gRPC 和 Thrift 在底层运输数据包都是采用的内核提供的 API 进行发包的。这些 RPC 框架在应用层之上提供了一种结构化的、高效的远程调用机制,使开发者能够更轻松地构建分布式系统。虽然它们通常在应用层协议的基础上构建,但它们自身更类似于框架或库,提供了更高级别的抽象,用于处理远程服务调用的复杂性。
gRPC 使用 Protocol Buffers(ProtoBuf)作为接口定义语言(IDL),这允许开发者定义服务接口、消息格式等,而不用关心底层通信细节。这里围绕的 gRPC 来讨论这个问题,了解 gRPC 协议都知道该协议是基于 HTTP/2 协议,利用了 HTTP/2 的多路复用、头部压缩、二进制帧提供了更高效的网络传输,相比 HTTP/1.1 使用多个 TCP 连接,每个连接只能传输一个请求和响应,这可能导致 TCP 连接的浪费和性能瓶颈,而 HTTP/2 引入了多路复用的特性,允许多个请求和响应在同一 TCP 连接上并行传输,这样也减少了 TCP 连接的数量提高了性能。
对于需要可靠型网络数据传输的场景,使用 TCP 是一个最佳的选择,但是也并不意味着盲目的去使用它传输数据。 TCP 传输数据之前每次都是需要进行 3 次握手,这 3 个握手数据包是主要的耗时来源,延迟就此产生了,如果在一次性很短暂数据运输需求下,这就显得不是那么适用了,快速打开一个连接使用完成之后快速释放掉,很多应用层的网络程序都是跑在 TCP 协议之上,必须经过这个慢启动的过程。
HTTP/1.0 版本主要就是针对此种突发性连接的场景,获取到某个 HTML 内容立马断开 TCP 连接,完全没有利用好 TCP 协议,每次发送一个 HTTP 请求都需要经过一次 TCP 慢启动过程。