一次网页请求背后的连接
一次网页请求背后的连接
想成为一个优秀的前端,对互联网协议是必须要了解的。本文使用WireShark抓包工具,对一次网页请求背后的TCP连接、HTTP请求进行了详细的展示。对网页请求中浏览器使用的并行连接、持久连接以及TCP连接建立关闭的过程均有所分析讨论,对HTTP如何封装在TCP中进行数据请求以及数据的响应返回也有所展示。供学习交流之用。
TCP简介
本文从传输层的报文开始,下层网络IP层、链路层寻址不在这里讨论范围。可以查看相关资料补充计算机网络知识。
TCP和UDP是传输层
的2个协议。
UDP是一个简单的、尽力而为的数据报传输协议,它不能确保可靠传输。提供一种无连接的服务,不可靠但效率高,适合通信量较小或者延迟敏感的传输。
相对而言TCP(Transmission Control Protocol)能够提供可靠传输,这也决定了它高度的复杂性以及较大的系统开销。TCP的复杂性足以用一本专门的教材来讲解,这里我们只对其经典的三次握手、“四次挥手”以及基本报文格式进行简介,达到看懂wireshark抓获的封包的目的。
TCP报文格式
图1
TCP的报文格式如上图所示。孜孜不倦地工作在我们每日的互联网通信中,并将长期保持不变。所以你有大把的时光慢慢记住它。
这里特别需要用到的是红色的标志位部分,分别是:URG,ACK,PSH,RST,SYN,FIN。
其中在三次握手中十分重要的标志位:
ACK:这是非常常用的一个标志位,不仅仅在三次握手以及四次挥手中,该标志位的功能就是用于确认。该位置1时表示正确接收到了对方的报文。
SYN:同步序列号标志。在建立TCP连接时,一定会有一方主动端,一方被动端。网页请求中客户端浏览器就是主动端。当SYN为1而ACK为0时,这就是一个主动请求连接的报文。若对方同意连接,返回一个ACK和SYN均为1的接受报文。可以说它就是建立连接的一个标志。
FIN:在数据发送完毕,希望断开连接时,向对方发送一个FIN位置1的报文,表示我已经发送完毕。
还有一些需要说明的是图中红色的标志位上面的2排–32位序列号以及32位确认号。
先补充说明一点,TCP连接是一个全双工的连接,也就是连接的双方均可以在此连接上进行数据的收发操作。对于大块的数据,TCP的一个报文装不下,需要分成多个报文来发送,然而在实际的网络中,报文很可能经过不同的路由到达对方。报文到达的顺序是没办法保证的因此,32位序列号
就用来指明报文的顺序,其具体含义是本报文携带的数据部分,第一个字节的序号。
举例来说,假设现在有3394字节的数据需要传输(每个字节占用一个序号),每个TCP报文最多携带1424字节的数据,同时假设数据从序号1开始发送(这个序号不一定是1,你可以选定从其他序号开始发送,这个序号是在三次握手的过程中协商好的)。那么第一个TCP报文的32位序列号就为1,发送了1424个字节。那么第二个TCP报文的32位序列号就从1425开始,第三个就为1424+1424的下一个2849开始。
刚才说了,TCP是全双工的连接,发送方在发送数据的同时也会接收数据。32位确认号
就是告诉对方我已经成功接收的数据序号是多少。我们现在转换角色,假设我们是上面发送3394数据的接收方,我已经正确接收了上面的第一个报文,也就是我正确接收到了1到1424字节序号,那么我在发回的报文中将会把32位确认号写为1425(这里正确接收到了1424序号,但TCP自动将其加1,只是为了方便表示我希望接收的下一个字节序号是1425)。注意,只有在ACK标志位置1时该字段才有意义,ACK置1表明确认接收。还有,收发双方选择的起始发送序号不一定相同,比如我选择从1序号开始发,你可以选择从1024序号开始发,序号只是一个编号而已,彼此根据这个编号进行确认就可以了。
下面我们还会具体分析一次网页请求的报文。
TCP三次握手
TCP是面向连接的协议,建立连接需要进行经典的3次握手,为什么一定要进行三次握手,你可以自行查阅资料。
三次握手的过程如下:
图2
在网页请求中,首先客户浏览器端向服务器发送一个SYN为1的报文,其中包含一个自己选定的初始的32位序列号x,这是第一次握手。
对方收到该请求后,如果同意建立连接,返回一个ACK和SYN标志位均为1的确认报文,将该报文的32位确认号写为x+1,与此同时,自己选定一个初始32位序列号y,这是第二次握手。
第三次握手,发起请求方收到了确认回复之后,返回一个ACK为1的确认报文,其中的32位确认号为y+1。至此连接建立。客户端将从自己设定的x+1序号开始发送数据。
这里我们使用wireshark对进行抓包,该网站是我部署在腾讯云的小主页。打开浏览器,请求该网页。抓到下面的封包:
图3
可以把图放大看,这里红线圈出来的3条就是3次握手的过程。可能看不太清,我下面会逐一对单个报文截图。
我们看到在三次握手中间还夹杂了其他的TCP包,实际上在一次网页请求中,不止建立了一个TCP端到端的连接!我们下面会说,这里我们只需要关注用红色圈起来的3个报文。
第一条:
图4
这里我们暂时不关注其他层。但是从下面第一条蓝色上面的网络IP层可看到
Internet Protocol Version 4, Src:115.156.245.180, Dst: 115.159.81.187
这是网络层的内容,它负责IP寻址,其中封装了手法双方的IP信息。加上Transmission Control Protocol中的内容:
Source Port: 60545
Destination Port: 80
可以看出这是从本机115.156.245.180:60545端口到目标主机115.159.81.187:80端口的连接,http服务默认端口就是80。我们看蓝色的Flags:0x002(SYN)
,可知这是一个TCP请求连接的报文,也就是第一次握手。注意看Sequence number:0,发送方将初始发送序号x选择成了0。
tip: ip+端口号 就是一个套接字
第二条:
图5
同上,我们可以看到这是一个从目标主机115.159.81.187:80端口发到本机115.156.245.180:60545端口的报文。其中Flags: 0x12(SYN, ACK),SYN、ACK置1,表明对方同意建立连接。这是第二次握手。回复的Acknowledgment number: 1也就是32位确认序列号,为第一次握手的x+1(第一次放松选择的x是0)。同时自己选择的初始发送序号Sequence number:0也为0。
第三条:
图6
这是第三次握手,由本机60545端口发向目标主机80端口一个ACK确认报文。
红色部分,回复的Acknowledgment number为第二次握手服务器方选定的Sequence number+1。至此连接建立。
发送第一个HTTP请求,获取HTML文档
紧接着三次握手建立连接之后,就是一次http请求:
CSDN-Ada助手: 非常感谢CSDN博主的分享,这篇博客对于想要学习排序算法的Javascript开发者来说非常有用。我觉得下一篇博客可以继续深入探讨JavaScript的数据结构和算法,比如二叉树、图、递归等等。这样的技术文章对其他用户也会非常有帮助,希望你能继续分享你的知识和经验,相信会有更多读者受益。 为了方便博主创作,提高生产力,CSDN上线了AI写作助手功能,就在创作编辑器右侧哦~(https://mp.csdn.net/edit?utm_source=blog_comment_recall )诚邀您来加入测评,到此(https://activity.csdn.net/creatActivity?id=10450&utm_source=blog_comment_recall)发布测评文章即可获得「话题勋章」,同时还有机会拿定制奖牌。
八火明灯: 后续兄弟选择器(~):和相邻兄弟选择器类似,但它会选取后面的全部兄弟元素
zjf_china007: 很棒,按照步骤操作,可行
od400: 一脸懵逼
A.张小震: 没有图片那