2.1创建套接字

2.1.1协议栈的内部结构

浏览器、邮件等一般应用程序收发数据用TCP;   

DNS查询等收发较短的控制数据用UDP

在互联网上传送数据时,数据会被切分成一个一个的网络包,而将网络包发送给通信对象的操作就是由IP来负责的,此外,IP中还包括ICMP协议和ARP协议

ICMP用于告知网络中包传送过程中产生的错误以及各种控制信息,ARP用于根据IP地址查询相应的以太网MAC地址

 

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

在协议栈的内部有一块用于存放控制信息的内存空间,这里记录了用于控制通信操作的控制信息,例如通信对象的IP地址,端口号,通信操作的进行状态等。本来套接字就只是一个概念而已,并不存在实体,如果一定要赋予它一个实体,我们就说这些控制信息就是套接字的实体。

套接字中记录了用于控制通信操作的各种控制信息,协议栈则需要根据这些信息判断下一步的行动,这就是套接字的作用

如下图显示套接字内容

 

2.1.3调用socket时的操作

创建套接字时,首先分配一个套接字所需的内存空间,然后向其中写入初始状态。接下来,需要将表示这个套接字的描述符告知应用程序,收到描述符之后,应用程序在向协议栈进行收发数据委托时就需要提供这个描述符

 

2.2连接服务器(连接实际上是通信双方交换控制信息)

2.2.1连接是什么意思

套接字刚刚创建完成的时候,里面并没有存放任何数据,也不知道通信的对象是谁。浏览器可以根据网址来查询服务器的IP地址,而且根据规则也知道应该使用

80号端口,我们需要把服务器的IP地址和端口号等信息告知协议栈,这就是连接操作的目的之一

服务器上也会创建套接字,但服务器上的协议栈和客户端一样,只创建套接字并不知道和谁通信。而且。链服务器上的应用程序也不知道通信对象是谁。

于是,我们需要让客户端向服务器告知必要的信息。客户端向服务器传达开始通信的请求,也是连接操作的目的之一

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

 控制信息大体上分为两类,第一类是客服端和服务器相互联络交换时的控制信息。整个通信过程中都需要,这些内容在TCP协议的规格中进行了定义

TCP头部格式

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

 

2.2.3连接操作的实际过程

这个过程是从应用程序调用Socket库中的connect开始的

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

上面的调用模块提供了服务器的IP地址和端口号,这些信息会被传递给协议栈中的TCP模块。

然后,TCP模块会与服务器的TCP模块交换控制信息,这一交互过程包含下面几个步骤

       客户端先创建一个包含表示开始数据收发操作的控制信息的头部

      头部包含很短字段,这里要关注的重点是发送方和接收方的端口号。到这里,客户端(发送方)的套接字就准确找到了服务器(接收方)的套接字

      将头部中的控制位SYN比特设置为1,大家可以认为它表示连接。

      此外还需要设置适当的序号和窗口大小

当TCP头部创建好之后,接下来TCP模块会将信息传递给IP模块并委托它进行发送。IP模块执行网络包发送操作后,网络包就会通过网络到达服务器,然后服务器的IP模块会将接收到的数据传递给TCP模块,服务器的TCP模块根据TCP头部中的信息找到端口号对应的套接字。当找到对应的套接字之后,套接字中会写入相应的信息,并将状态改为正在连接。

上述操作完成后,服务器的TCP模块会返回响应,这个过程和客户端一样,需要在TCP头部中设置发送方和接收方的端口号以及SYN比特,此外,在返回响应时还需要将ACK控制位设为1,这表示已经接收到相应的网络包,双方通信时必须互相确认网络包是否已经到达,而设置ACK比特就是用来进行这一确认。相应的,客服端也需要将ACK比特设置为1并发给服务器,告诉服务器刚才的响应包已经收到,当这个服务器收到这个返回包之后,连接操作才算全部完成。

 

2.3收发数据

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

数据收发操作是从应用程序调用write将要发送的数据交给协议栈开始的。协议栈并不关心应用数据传来的数据是什么内容,在协议栈看来,要发送的数据就是一定长度的二进制字节序列而已

协议栈并不是一收到数据就马上发送出去的,而是将数据存放在内部的发送缓存区中,并等待应用程序的下一段数据。

协议栈会根据一个叫做MTU的参数来进行判断。MTU表示一个网络包的最大长度,在以太网中一般是1500字节。MTU是包含头部的总长度,因此需要从MTU减去头部的总长度,得到一个网络中所能容纳的最大数据长度,这一长度叫作MSS。协议栈的内部有一个计时器,当经过一定时间之后,就会把网络包发送出去。

 

2.3.2对较大的数据进行查分

HTTP请求消息一般不会太长,一个网络包就能装得下,但如果其中要提交表单数据,长度就可能超过一个网络包所能容纳的数据量

 

2.3.3 使用ACK号确认网络包已收到

TCP具备确认对方是否成功收到网络包,以及当对方没收到时进行重发的功能。

 

2.3.4根据网络包平均往返时间调整ACK号等待时间

当网络传输繁忙时就会发生拥塞,ACK号的返回就会变慢,ACK号的返回时间会产生很大的波动,TCP采用了动态调整等待时间的方法。

 

2.3.5使用窗口有效管理ACK号

每发送一个包就等待一个ACK好的方式是最简单的,但在等待ACK号的这段时间中,如果什么都不做那就太浪费了。TCP采用了滑动窗口方式来管理数据发送和ACK号的操作。

 

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

首先,服务器一方的应用程序会调用Socket库中的close程序。然后服务器的协议栈会生成包含断开信息的TCP头部,具体来说就是将控制位中的FIN比特设为1

 

2.4.2 删除套接字