网络是怎样连接的学习笔记(二)

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

2.1创建套接字

2.1.1协议栈的内部结构

操作系统的网络控制软件(协议栈)的内部结构如下:


图中最上面的部分是网络应用程序,它会将收发数据等操作委托给下层的部分来完成。

应用程序的下面是Socket库,其中包括解析器,解析器用来向DNS服务器发出查询。

在下面就是操作系统内部了,其中包括协议栈。协议栈的上半部分有两块,分别是用TCP协议收发数据的部分和用UDP收发数据的部分,他们会接受应用程序的委托,执行收发数据的操作。像浏览器、邮件等一般的应用程序使用都是使用TCP收发数据的,而像DNS等收发较短的控制数据的时候则使用UDP。

下面一半是用IP协议控制网络收发操作的部分。在互联网上传送数据时,数据会被切分为一个一个的网络包,而将网络包发送给通信对象的操作就是由IP来负责的。此外IP协议还包括ICMP协议和ARP协议。ICMP协议用来告知网络包传送过程中产生的错误以及各种控制信息,ARP协议用于根据IP协议查询相应的以太网MAC地址。

IP下面的网卡驱动程序负责控制网卡硬件,而最下面的网卡完成实际的收发操作,也就是对网线中的信号执行发送和接收操作。

2.1.2套接字的实体就是通信控制信息

在协议栈的内部有一块用于存储通信控制信息的内存空间。例如通信对象的IP地址、端口号、通信操作的进行状态等。本来套接字就是一个概念,并不存在真正的实体,如果一定要赋予它一个实体,可以说这些控制信息就是套接字的实体,或者说存放控制信息的内存空间就是套接字的实体。

协议栈在执行操作时需要参阅这些控制信息。例如,在发送数据时,需要看一下套接字中的通信对象的IP地址和端口号,以便向指定的IP地址和端口号发送数据。在发送数据后,协议栈需要等待对方收到数据返回的响应信息,但数据也有可能中途丢失,永远也等不到对方的响应。在这样的情况下,我们不能一直等下去,需要在等待一定时间之后重新发送丢失

的数据,这就需要协议栈能够知道执行发送数据操作后过了多长时间。为此,套接字中必须要记录是否已经收到响应,以及发送数据后经过了多长时间,才能根据这些信息按照需要执行重发操作。协议栈是根据套接字中记录的控制信息来工作的。

在Windows中可以用netstat -ano命令显示套接字内容。

2.1.3调用socket时的操作

浏览器通过Socket库向协议栈发出委托的一系列操作。浏览器委托协议栈使用TCP协议来收发数据。首先是创建套接字的阶段,应用程序调用socket申请创建套接字,协议栈根据应用程序的申请执行创建套接字的操作。在这个过程中,协议栈首先会分配用于存放一个套接字所需的内存空间。这相当于为控制信息准备一个容器。套接字刚刚创建时,数据收发操作还没有开始,因此需要在套接字的内存空间中写入表示这一初始状态的控制信息。到这里,创建套接字的操作就完成了。

接下来,需要将表示这个套接字的描述符告知应用程序。描述符相当于用来区分协议栈中的多个套接字的号码牌。收到描述符之后,应用程序在向协议栈进行收发数据委托时就需要提供这个描述符。由于套接字中记录了通信双方的信息以及通信处于怎样的状态,所以只要通过描述符确定了相应的套接字,协议栈就能够获取所有的相关信息,这样一来,应用程序就不需要每次都告诉协议栈应该和谁进行通信了。

2.2连接服务器

2.2.1连接的含义

创建套接字之后,应用程序(浏览器)就会调用connect,随后协议栈会将本地的套接字与服务器的套接字进行连接。连接实际上是通信双方交换控制信息,在套接字中记录这些必要信息并准备数据收发的一连串操作。套接字刚刚创建完成的时候,里面并没有存放任何数据,也不知道通信的对象是谁。浏览器可以根据网址来查询服务器的IP 地址,而且根据规则也知道应该使用80 号端口,但只有浏览器知道这些必要的信息是不够的,因为在调用socket 创建套接字时,这些信息并没有传递给协议栈。因此,我们需要把服务器的IP 地址和端口号等信息告知协议栈,这是连接操作的目的之一。

服务器上也有套接字,但服务器上的协议栈和客户端上的一样,只创建了套接字不知道和谁通信。并且服务器上的应用程序也不知道和谁通信。因此需要让客户端告知服务器必要的信息。所以,客户端向服务器传达开始通信的请求也是连接操作的目的之一。

此外,当执行数据收发操作时,还需要一块用来临时存放收发数据的内存空间,这块内存空间称为缓冲区,它也是连接操作的过程中分配的。

连接的目的:

(1)把服务器的IP 地址和端口号等信息告知协议栈。

(2)客户端向服务器传达开始通信的请求,将本机的IP地址和端口号告知服务器。

(3)创建用于执行数据收发操作的内存空间。

2.2.2负责保存控制信息的头部

通信操作中使用的控制信息分为两类。

(1)头部中记录的信息(以太网头部、IP头部、TCP头部)

(2)套接字(协议栈中的内存空间)中记录的信息

控制信息可以分为两类,第一类是客户端和服务器相互联络时交换的控制信息,这些内容在TCP 协议的规格中进行了定义。这些字段是固定的,在连接、收发、断开等各个阶段中,每次客户端和服务器之间进行通信时,都需要提供这些控制信息。这些信息会被添加在客户端与服务器之间传递的网络包的开头。在连接阶段,由于数据收发还没有开始,网络包中没有实际的数据,只有控制信息。

TCP头部的格式:


控制信息还有另外一类,那就是保存在套接字中,用来控制协议栈操作的信息。应用程序传递来的信息以及从通信对象接收到的信息都会保存在这里,还有收发数据操作的执行状态等信息也会保存在这里,协议栈会根据这些信息来执行每一步的操作。我们可以说,套接字的控制信息和协

议栈的程序本身其实是一体的,因此,“协议栈具体需要哪些信息”会根据协议栈本身的实现方式不同而不同,但这并没有什么问题。因为协议栈中的控制信息通信对方是看不见的,只要在通信时按照规则将必要的信息写入头部,客户端和服务器之间的通信就能够得以成立。例如,Windows 和Linux 操作系统的内部结构不同,协议栈的实现方式不同,必要的控制信息也就不同。但即便如此,两种系统之间依然能够互相通信,同样地,计算机和手机之间也能够互相通信。

2.2.3连接操作的实际过程

连接操作是从应用程序调用Socket库的connect开始的。

connect(< 描述符>, < 服务器IP 地址和端口号>, …)

上面的调用提供了服务器的IP地址和端口号,这些信息会传递给协议栈中的TCP模块。然后,TCP 模块会与该IP地址对应的对象,也就是与服务器的TCP模块交换控制信息。

首先,客户端先创建一个包含表示开始数据收发操作的控制信息的头部。头部包含很多字段,这里要关注的重点是发送方和接收方的端口号。到这里,客户端(发送方)的套接字就准确找到了服务器(接收方)的套接字,也就是搞清楚了我应该连接哪个套接字。然后,我们将头部中的控制位的SYN比特设置为1,大家可以认为它表示连接。此外还需要设置适当的序号和窗口大小。

连接操作的第一步是在TCP模块处创建表示连接控制信息的头部。

通过TCP头部中的发送方和接收方端口号可以找到要连接的套接字。

当TCP头部创建好之后,接下来TCP模块会将信息传递给IP模块并委托它进行发送。IP模块执行网络包发送操作后,网络包就会通过网络到达服务器,然后服务器上的IP模块会将接收到的数据传递给TCP模块,服务器的TCP模块根据TCP头部中的信息找到端口号对应的套接字,也就是说,从处于等待连接状态的套接字中找到与TCP头部中记录的端口号相同的套接字就可以了。当找到对应的套接字之后,套接字中会写入相应的信息,并将状态改为正在连接。上述操作完成后,服务器的TCP模块会返回响应,这个过程和客户端一样,需要在TCP头部中设置发送方和接收方端口号以及SYN比特。此外,在返回响应时还需要将ACK控制位设为1(客户端向服务器发送第一个网络包时,由于服务器还没有接收过网络包,所以需要将ACK比特设为0),这表示已经接收到相应的网络包。网络中经常会发生错误,网络包也会发生丢失,因此双方在通信时必须相互确认网络包是否已经送达,而设置ACK比特就是用来进行这一确认的。接下来,服务器TCP模块会将TCP头部传递给IP模块,并委托IP模块向客户端返回响应。

然后,网络包就会返回到客户端,通过IP模块到达TCP模块,并通过TCP头部的信息确认连接服务器的操作是否成功。如果SYN为1则表示连接成功,这时会向套接字中写入服务器的IP地址、端口号等信息,同时还会将状态改为连接完毕。刚才服务器返回响应时将ACK比特设置为1,相应地,客户端也需要将ACK比特设置为1并发回服务器,告诉服务器刚才的响应包已经收到。当这个服务器收到这个返回包之后,连接操作才算全部完成。

建立连接之后,协议栈的连接操作就结束了,也就是说connect已经执行完毕,控制流程被交回到应用程序。

2.3收发数据

2.3.1将HTTP请求消息交给协议栈

当控制流程从connect回到应用程序之后,接下来就进入数据收发阶段了。数据收发操作是从应用程序调用write将要发送的数据交给协议栈开始的。协议栈收到数据后执行发送操作。

协议栈并不关心应用程序传来的数据是什么内容。协议栈也并不是一收到数据就马上发送出去,而是会将数据存放在内部的发送缓冲区中,并等待应用程序的下一段数据。一次将多少数据交给协议栈是由应用程序自行决定的,协议栈并不能控制这一行为。在这样的情况下,

如果一收到数据就马上发送出去,就可能会发送大量的小包,导致网络效率下降,因此需要在数据积累到一定量时再发送出去。至于要积累多少数据才能发送,不同种类和版本的操作系统会有所不同,不能一概而论,但都是根据下面几个要素来判断的。

(1)第一个判断要素是每个网络包能容纳的数据长度,协议栈会根据一个叫作MTU(Maximum TransmissionUnit,最大传输单元)的参数来进行判断。MTU表示一个网络包的最大长度,在以太网中一般是1500 字节。。MTU 是包含头部的总长度,因此需要从MTU 减去头部的长度,然后得到的长度就是一个网络包中所能容纳的最大数据长度,这一长度叫作MSS。当从应用程序收到的数据长度超过或者接近MSS(Maximum Segment Size,最大分段大小。 TCP 和IP 的头部加起来一般是40 字节,因此MTU减去这个长度就是MSS。例如,在以太网中,MTU为1500,因此MSS就是1460)时再发送出去,就可以避免发送大量小包的问题了。

MTU:一个网络包的最大长度,以太网中一般为1500 字节。

MSS:除去头部之后,一个网络包所能容纳的TCP 数据的最大长度。

(2)另一个判断要素是时间。当应用程序发送数据的频率不高的时候,如果每次都等到长度接近MSS 时再发送,可能会因为等待时间太长而造成发送延迟,这种情况下,即便缓冲区中的数据长度没有达到MSS,也应该果断发送出去。为此,协议栈的内部有一个计时器,当经过一定时间之后,就会把网络包发送出去。

MTU与MSS


2.3.2对较大的数据进行拆分

HTTP请求消息一般不会很长,一个网络包就能装得下,但如果其中要提交表单数据,长

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值