我是靠谱客的博主 大力鞋垫,最近开发中收集的这篇文章主要介绍《网络是怎样连接的》读书笔记2-探索协议栈和网卡第二章 用电信号传输TCP/IP数据(探索协议栈和网卡),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

第二章 用电信号传输TCP/IP数据(探索协议栈和网卡)

一、创建套接字

二、连接服务器

三、收发数据

四、从服务器断开并删除套接字

五、IP与以太网的包收发操作

六、UDP协议的收发操作


第二章 用电信号传输TCP/IP数据(探索协议栈和网卡)

一、创建套接字

1. 协议栈的内部结构

协议栈的上半部分有两块,分别是负责用TCP协议收发数据的部分和负责用UDP协议收发数据的部分,它们会接受应用程序的委托执行收发数据的操作。像浏览器、邮件等一般的应用程序都是使用TCP收发数据的,而像DNS查询等收发较短的控制数据的时候则使用UDP。下面一半是用IP协议控制网络包收发操作的部分,网络包发送给通信对象的操作就是由IP来负责。ICMP用于告知网络包传送过程中产生的错误以及各种控制消息,ARP用于根据IP地址查询相应的以太网MAC地址。IP下面的网卡驱动程序负责控制网卡硬件,而最下面的网卡则负责完成实际的收发操作,也就是对网线中的信号执行发送和接收的操作。

2. 套接字的实体就是通信控制信息(或者说存放控制信息的内存空间就是套接字的实体),协议栈是根据套接字中记录的控制信息来工作的,这也就是套接字的作用。Windows中可以用netstat命令显示套接字内容:

3. 创建套接字时,首先分配一个套接字所需的内存空间,然后向其中写入初始状态。接下来,需要将表示这个套接字的描述符告知应用程序。应用程序将收到的描述符存放在内存中。描述符是用来识别不同的套接字的,可作如下理解:计算机中会同时进行多个数据的通信操作,比如可以打开两个浏览器窗口,同时访问两台Web服务器。这时,有两个数据收发操作在同时进行,也就需要创建两个不同的套接字。这说明同一台计算机上可能同时存在多个套接字,我们就需要描述符来识别出某个特定的套接字。收到描述符之后,应用程序在向协议栈进行收发数据委托时就需要提供这个描述符。由于套接字中记录了通信双方的信息以及通信处于怎样的状态,所以只要通过描述符确定了相应的套接字,协议栈就能够获取所有的相关信息,这样一来,应用程序就不需要每次都告诉协议栈应该和谁进行通信了。

二、连接服务器

1. 连接实际上是通信双方交换控制信息,在套接字中记录这些必要信息并准备数据收发的一连串操作。通信操作中使用的控制信息分为两类:(1)头部中记录的信息,(2)套接字(协议栈中的内存空间,应用程序传递来的信息以及从通信对象接收到的信息都会保存在这里,还有收发数据操作的执行状态等信息也会保存在这里)中记录的信息。当执行数据收发操作时,我们还需要一块用来临时存放要收发的数据的内存空间,这块内存空间称为缓冲区,它也是在连接操作的过程中分配的。

2. 套接字刚刚创建完成的时候,里面并没有存放任何数据,我们需要把服务器的IP地址和端口号等信息告知协议栈,这是连接操作的目的之一。服务器上也会创建套接字,但只创建套接字是不知道应该和谁进行通信的,需要客户端向服务器传达开始通信的请求,也是连接操作的目的之一。

3. 负责保存控制信息的TCP头部

4.  连接的流程是从应用程序调用Socket库的connect开始的。connect(<描述符>,<服务器IP和端口>,…)

     具体关键步骤:

(1)第一步是在客户端TCP模块处创建表示连接控制信息的头部

(2)TCP模块将信息传递给IP模块,由IP模块发至服务器

(3)服务器IP模块将接收到的信息传递给TCP模块(TCP模块根据TCP头部中的信息找到端口号对应的套接字)

(4)当找到对应的套接字之后,套接字中会写入相应的信息,并将状态改为正在连接

(5)服务器的TCP模块会返回响应,过程和客户端一样,需要在TCP头部中设置发送方和接收方端口号以及SYN比特。此外,在返回响应时还需要将ACK控制位设为1,这表示已经接收到相应的网络包

(6)网络包返回到客户端,查看TCP头部的信息,如果SYN为1则表示连接成功。客户端也需要将ACK比特设置为1并发回服务器,当服务器收到这个返回包之后,连接操作才算全部完成

三、收发数据

1. 首先应用程序将HTTP请求消息交给协议栈,一次将多少数据交给协议栈是由应用程序自行决定的。协议栈并不是一收到数据就马上发送出去,而是会将数据存放在内部的发送缓冲区中。要积累多少数据才能发送,不同种类和版本的操作系统会有所不同。第一个判断要素是每个网络包能容纳的数据长度(应用程序收到的数据长度超过或者接近MSS时再发送出去,如下图)。另一个判断要素是时间,协议栈有一个计时器,当应用程序发送数据的频率不高的时,经过一定时间之后,就算MSS未满也会把网络包发送出去。在进行发送操作时需要综合考虑这两个要素以达到平衡。不过,TCP协议规格中并没有告诉我们怎样才能平衡,因此实际如何判断是由协议栈的开发者来决定的。有时,应用程序在发送数据时也可以指定一些选项,比如如果指定“不等待填满缓冲区直接发送”,则协议栈就会按照要求直接发送数据。

2. 当HTTP消息过长时,就可能超过一个网络包所能容纳的数据量。这时需要对较大的数据进行拆分。当判断需要发送这些数据时,就在每一块数据前面加上TCP头部,并根据套接字中记录的控制信息标记发送方和接收方的端口号,然后交给IP模块来执行发送数据的操作。

3. 通过“序号”和“ACK号”可以确认接收方是否收到了网络包。

在实际的通信中,序号并不是从1开始的,而是需要用随机数计算出一个初始值,这是因为如果序号都从1开始,通信过程就会非常容易预测,有人会利用这一点来发动攻击。在之前的连接(connect)过程中,有一个将SYN控制位设为1并发送给服务器的操作,就是在这一步将序号的初始值告知对方的。实际上,在将SYN设为1的同时,还需要同时设置序号字段的值,而这里的值就代表序号的初始值。

4. TCP采用序号和ACK号的交互方式确认对方是否收到了数据,在得到对方确认之前,发送过的包都会保存在发送缓冲区中。如果对方没有返回某些包对应的ACK号,那么就重新发送这些包。在等待ACK号时,TCP会根据网络包平均往返时间调整ACK号等待时间。有了这一机制,我们就不需要在其他地方对错误进行补救了。因此,网卡、集线器、路由器都没有错误补偿机制。

5. 滑动窗口,就是在发送一个包之后,不等待ACK号返回,而是直接发送后续的一系列包。这样一来,等待ACK号的这段时间就被有效利用起来了。

当接收方的TCP收到包后,会先将数据存放到接收缓冲区中。然后,接收方需要计算ACK号,将数据块组装起来还原成原本的数据并传递给应用程序,如果这些操作还没完成下一个包就到了,包会被暂存在接收缓冲区中。如果数据到达的速率比处理数据并传递给应用程序的速率还要快,那么接收缓冲区中的数据会越堆越多,最后就会溢出,后面的数据也就进不来了。我们可以通过下面的方法来避免这种情况的发生。首先,接收方需要告诉发送方自己最多能接收多少数据,然后发送方根据这个值对数据发送操作进行控制,这就是滑动窗口方式的基本思路。能够接收的最大数据量称为窗口大小,它是TCP调优参数中非常有名的一个

6. 接收方在发送ACK号和窗口更新时,并不会马上把包发送出去,而是会等待一段时间,在这个过程中很有可能会出现其他的通知操作,这样就可以把两种通知合并在一个包里面发送了。当需要连续发送ACK号时,只要发送最后一个ACK号就可以了,中间的可以全部省略。当需要连续发送多个窗口更新时也可以减少包的数量,因为连续发生窗口更新说明应用程序连续请求了数据,接收缓冲区的剩余空间连续增加。这种情况和ACK号一样,可以省略中间过程,只要发送最终的结果就可以了。

7. 接收HTTP响应消息

首先,协议栈会检查收到的数据块和TCP头部的内容,判断是否有数据丢失,如果没有问题则返回ACK号。然后,协议栈将数据块暂存到接收缓冲区中,并将数据块按顺序连接起来还原出原始的数据,最后将数据交给应用程序。具体来说,协议栈会将接收到的数据复制到应用程序指定的内存地址中,然后将控制流程交回应用程序。将数据交给应用程序之后,协议栈还需要找到合适的时机向发送方发送窗口更新。

四、从服务器断开并删除套接字

1. 数据发送完毕后断开连接

2. 断开连接不马上删除套接字的原因:如果最后客户端返回的ACK号丢失了,这时服务器没有接收到ACK号,可能会重发一次FIN。如果这时客户端的套接字已经删除了,那么套接字中保存的控制信息也就跟着消失了,套接字对应的端口号就会被释放出来。这时,如果别的应用程序要创建套接字,新套接字碰巧又被分配了同一个端口号,而服务器重发的FIN正好到达,本来这个FIN是要发给刚刚删除的那个套接字的,但新套接字具有相同的端口号,于是这个FIN就会错误地跑到新套接字里面,新套接字就开始执行断开操作了。

3. 整个数据收发流程小结:

a. 数据收发操作的第一步是创建套接字。一般来说,服务器一方的应用程序在启动时就会创建好套接字并进入等待连接的状态。客户端则一般是在用户触发特定动作,需要访问服务器的时候创建套接字。在这个阶段,还没有开始传输网络包。

b. 创建套接字之后,客户端会向服务器发起连接操作。首先,客户端会生成一个SYN为1的TCP包并发送给服务器。这个TCP包的头部还包含了客户端向服务器发送数据时使用的初始序号,以及服务器向客户端发送数据时需要用到的窗口大小。当这个包到达服务器之后,服务器会返回一个SYN为1的TCP包,这个包的头部中也包含了序号和窗口大小,此外还包含表示确认已收到包的ACK号。当这个包到达客户端时,客户端会向服务器返回一个包含表示确认的ACK号的TCP包。到这里,连接操作就完成了,双方进入数据收发阶段。

c. 数据收发阶段的操作根据应用程序的不同而有一些差异,以Web为例,首先客户端会向服务器发送请求消息。TCP会将请求消息切分成一定大小的块,并在每一块前面加上TCP头部,然后发送给服务器。TCP头部中包含序号,它表示当前发送的是第几个字节的数据。当服务器收到数据时,会向客户端返回ACK号。在最初的阶段,服务器只是不断接收数据,随着数据收发的进行,数据不断传递给应用程序,接收缓冲区就会被逐步释放。这时,服务器需要将新的窗口大小告知客户端。当服务器收到客户端的请求消息后,会向客户端返回响应消息,这个过程和刚才的过程正好相反。

d. 服务器的响应消息发送完毕之后,数据收发操作就结束了,这时就会开始执行断开操作。以Web为例,服务器会先发起断开过程(也可由客户端发起)。在这个过程中,服务器先发送一个FIN为1的TCP包,然后客户端返回一个表示确认收到的ACK号。接下来,双方还会交换一组方向相反的FIN为1的TCP包和包含ACK号的TCP包。最后,在等待一段时间后,套接字会被删除。

五、IP与以太网的包收发操作

1. 包的基本结构

2. 路由器和集线器两种不同的转发设备,它们在传输网络包时有着各自的分工。

(1)路由器根据目标地址判断下一个路由器的位置

(2)集线器在子网中将网络包传输到下一个路由

实际上,集线器是按照以太网规则传输包的设备,而路由器是按照IP规则传输包的设备,因此我们也可以作如下理解。

(1)IP协议根据目标地址判断下一个IP转发设备的位置

(2)子网中的以太网协议将包传输到下一个转发设备

3. TCP/IP包包含如下两个头部。(a)MAC头部(用于以太网协议)  (b)IP头部(用于IP协议)

4. 包收发流程

5. IP模块负责添加如下两个头部。(1) MAC头部:以太网用的头部,包含MAC地址(2)IP头部:IP用的头部,包含IP地址

6. 路由表(发送方判断使用哪个网卡发送或路由器判断下一个路由器位置)

    IP模块根据路由表Gateway栏的内容判断应该把包发送给谁。

7. 通过ARP查询目标路由器的MAC地址

8. 网卡会将IP包转换成电或光信号发送出去

注:网卡的ROM中保存着全世界唯一的MAC地址,这是在生产网卡时写入的。网卡中保存的MAC地址会由网卡驱动程序读取(从ROM或者命令或者配置文件中读取MAC地址)并分配给MAC模块。

流程:网卡驱动从IP模块获取包之后,会将其复制到网卡内的缓冲区中,然后向MAC模块发送发送包的命令。接下来就轮到MAC模块进行工作了。首先,MAC模块会将包从缓冲区中取出,并在开头加上报头和起始帧分界符,在末尾加上用于检测错误的帧校验序列。每个包的前面都有报头和起始帧分界符(SFD),报头用来测定时机,SFD用来确定数据包的起始位置。末尾的FCS(帧校验序列)用来检查包传输过程中因噪声导致的波形紊乱、数据错误,它是一串32比特的序列,是通过一个公式对包中从头到尾的所有内容进行计算而得出来的。网卡的MAC模块生成通用信号,然后由PHY(MAU)模块转换成可在网线中传输的格式,并通过网线发送出去。

六、UDP协议的收发操作

UDP没有TCP的接收确认、窗口等机制,因此在收发数据之前也不需要交换控制信息,也就是说不需要建立和断开连接的步骤,只要在从应用程序获取的数据前面加上UDP头部,然后交给IP进行发送就可以了。接收也很简单,只要根据IP头部中的接收方和发送方IP地址,以及UDP头部中的接收方和发送方端口号,找到相应的套接字并将数据交给相应的应用程序就可以了。

最后

以上就是大力鞋垫为你收集整理的《网络是怎样连接的》读书笔记2-探索协议栈和网卡第二章 用电信号传输TCP/IP数据(探索协议栈和网卡)的全部内容,希望文章能够帮你解决《网络是怎样连接的》读书笔记2-探索协议栈和网卡第二章 用电信号传输TCP/IP数据(探索协议栈和网卡)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(73)

评论列表共有 0 条评论

立即
投稿
返回
顶部