前言
你好奇之前学习的http协议、七层/四层网络模型和业务代码中的一次网络请求过程是怎么联系起来的吗? 你好奇框架封装的http请求和原生请求的区别在哪里吗?感兴趣的话,一起来看一下吧。
注:因微信平台封禁外部链接,所有参考文献链接均在文末。
七层/四层网络模型
七层/四层模型到底有什么用?其实,没啥用。哦,不,是对一般互联网产品开发人员来说没啥用。它就是在解释一个网络请求的的数据传输链路,代码开发中,没有特殊需求,是不用操作这些的。完整2020版网络协议图可参见:网络通讯协议-2020.pdf
以四层模型为例,上面第4层(应用层)就是日常研发人员写的接口操作的那一层。当这个网络请求的接口函数被执行之后,会根据下面的1,2,3层协议进行传输协议确认、路由分发、寻址之后到达下面的链路层,然后链路层实现数据的传输。
http协议&tcp协议
好多人把http协议和tcp协议混淆。其实,http协议是一种网络消息规范。就好比是两个人要开始交流,大家先约定好说中文还是英语。如果一个人只懂中文,一个人只懂英语,那怎么能交流的上。两台计算机之间消息传输也是一样的,约定好用http协议,就都用这种协议,这样一台计算机发送出去的消息,另一台计算机才能解析出来。至于为什么用http协议,而不是其他协议,当然是一开始互联网诞生的时候,有人提出了http协议,大家就懒得改其他的协议了,既然大家都用这种,那我也用这种吧。不过,近年来因为企业架构体系的演进,相继出现了rpc协议,dubbo协议等。
而tcp是一种消息传输协议。它是约定了这条按照http协议封装的网络消息是如何传输的。类似于2个人约定好用中文沟通之后,选择什么途径交流,是面对面还是打电话或者写信。tcp 就是负责这个传输过程的,所以tcp协议属于传输层。
因此,http协议和tcp协议没啥竞争关系啦,一个属于应用层、一个属于传输层。它们经常一起被提到,是因为都是最常用的协议,最佳合作伙伴。就像刘国梁和张继科一样,但是属于不同赛道,哈哈哈。
Linux 网络请求
由于C/C++本身没有http通讯工具,因此一般会安装libcurl组件库,使得linux系统具有网络请求功能。
curl 安装过程:
1、使用linux 的系统安装命令
1 | 复制代码 yum install curl |
2、编译源码包进行安装
1 | 复制代码 (1)下载源代码 |
那么,curl 命令是如何发起这次的网络请求的?
我们可以查阅一下curl的源代码,确认具体的实现过程分析(具体还没看,后续补上)可以看这里:libcurl源代码分析。
如果不想看那么复杂的代码,可以看这个简版的一个博客:C语言实现http请求。从博客中的代码段可以看出,实现一次http请求,主要使用的c函数,除了strcat(字符串拼接)之外,还有几个比较关键的函数:inet_pton(ip地址转换函数)、socket 和 connect。
其中strcat 的作用就是封装http协议格式的消息,包括请求头、域名、端口、路由、发送消息内容、消息长度等。具体的请求报文和响应报文,可以看这里:http/https请求报文和响应报文。
根据socket函数详细解释soket函数,可知,其中一个参数用来标识是使用tcp还是udp协议传输,也就是我们上面提到的传输层协议的设置。当完成tcp协议的设置之后,调用connect函数会触发计算机与远端服务器进行连接,这个连接过程会经历我们常见的三次握手(TCP三次握手详解)。
至此,我们就介绍完了http协议和tcp协议具体在一次网络请求中是如何实现的。
网络数据传输过程
当消息按照http协议格式封装之后,并选择了tcp协议作为传输协议,计算机会调用网络层设备(路由器),进行路由的寻址,然后经过数据链路层发送数据。
这个过程从代码运行角度来分析,整体过程是高级语言(业务代码逻辑,也就是上面提到的消息处理逻辑)经过编译之后形成汇编语言、汇编语言执行CPU指令,CPU指令对计算机进行控制。然后计算机的数字信号(字节码)经过晶体管转换为模拟信号(电流信息),通过传输线路进行传输。到达对方计算机之后逆向执行该过程,得到请求数据。
CPU执行指令集,以及数字信号和模拟信号的转换解释,可以看这里:CPU指令集是如何执行的。
Java原生网络请求
JDK的java.net包中提供了访问http协议的基本功能类HttpURLConnection。具体的网络请求示例代码可以看这篇博客Java发起Http请求,从主要函数逻辑可以看出,Java发起网络请求同样也是经过了网络请求参数的设置:包括Host等信息,以及消息体的封装(所以,http和tcp协议才会被称为计算机组成的基本原理,而不同的语言栈编写业务代码,只不过是对原理的不同类型的实现。就像是买了怡宝和农夫山泉、他们都是水,只是品牌不同而已。因此才会有“语言只是实现工具”这种说法)。具体的消息发送底层原理也是通过socket进行发送的,相关源码分析可以看这里:HttpURLConnection源码分析。
由此可以看出,无论什么语言发起http网络请求,都需要遵循http协议规范的消息封装格式,选择tcp还是udp等传输协议,并调用socket进行消息的发送。而socket函数能够实现通信是因为计算机把高级编程语言最终编译为汇编语言,汇编语言执行了机器命令(CPU指令集等),控制内存单元、逻辑处理单元、以及外围电路进行工作。而外围电路中晶体管会将机器指令的数字信号转换为模拟信号,形成传输电流在电路中传输,当模拟信号传输到另一个消息接收设备的时候,再逆向执行这个过程,从而目标计算机可以获得当前计算机发送出去的消息,实现一次网络通信。
Spring 框架网络请求
框架是为了提升开发效率而实现的对底层函数的封装。Java的原生类库封装了socket函数实现了网络请求。但是使用起来不是特别优雅,而且代码比较冗余。
为了方便开发人员使用,同时降低代码的冗余率,Spring框架中的客户端网络请求函数同样是封装了Java的基础函数。Spring boot 常见的发起网络请求的方式除了上面的httpUrlConnection,还有httpClient、springBoot-restTemplate、closeableHttpClient 以及feign、openFeign。具体实现代码可以参考博客:Java中发起Http请求的常见方式。
π酱留言:本篇为初稿,后续不定时补充和完善细节
参考文献:
1、网络通讯协议-2020.pdf :www.colasoft.com.cn/download/ne…
2、curl码源编译安装:blog.csdn.net/peng3148995…
3、libcurl源代码分析:www.cnblogs.com/lidabo/p/45…
4、C语言实现http请求:www.jianshu.com/p/867632980…
5、http/https请求报文和响应报文:www.jianshu.com/p/64a64a049…
6、soket函数:baike.baidu.com 搜索socket函数
7、TCP三次握手详解:zhuanlan.zhihu.com/p/40013850
8、CPU指令集是如何执行的:zhidao.baidu.com/question/23…
9、Java发起Http请求:blog.csdn.net/qq_40036754…
10、HttpURLConnection源码分析:blog.csdn.net/Charon_Chui…
11、Java中发起Http请求的常见方式:blog.csdn.net/riemann_/ar…
转自微信公众号【程序媛的被窝】:mp.weixin.qq.com/s?__biz=Mzk…
本文转载自: 掘金