文章目录
  1. 创建套接字
    1. 协议栈的结构
    2. 套接字:通信控制信息
    3. socket的内部实现
  2. 连接服务器
    1. 连接:通信双方交换控制信息
    2. 保存控制信息的头部
    3. 连接的具体操作
  3. 收发数据
    1. 请求消息进入协议栈
    2. 对长数据进行拆分
    3. 网络包的接收确认
    4. ACK号等待时间
    5. 滑动窗口
    6. ACK与窗口信息的合并发送

创建套接字

协议栈的结构

 

套接字:通信控制信息

套接字记录着通信对象的IP地址与端口号、通信的状态等等;总之,套接字中记录了用于控制通信的各种信息,协议栈根据这些信息判断下一步操作。

socket的内部实现

以下所示是更详细的收发数据示意图:

连接服务器

连接:通信双方交换控制信息

所谓建立连接,就是为通信双方互相交换控制信息,在套接字中记录这些必要信息并准备数据收发的一系列操作。

保存控制信息的头部

在数据包的头部,存放着客户端与服务器相互联络所需的控制信息,这些信息在TCP协议中进行了定义,如下表所示。

 

 

在连接阶段,通信双方只交换控制信息,此时网络包的结构如下图:

 

 

通信双方建立连接之后,通信双方开始互相发送数据,此时的网络包结构如下图:

 

 

连接的具体操作

服务器端 方向 客户端
< 创建TCP头部,其中包含表示开始数据收发操作的控制信息;

对TCP头部进行初始化设置(源IP与目的IP、源端口与目的端口、SYN位置1、序号设置与窗口大小设置等等);

将TCP头部传给IP层并委托IP层发送给服务器端。
服务器端接收到数据,经以太层、IP层解析之后到达TCP层;

TCP层根据头部的目的端口号找到连接此请求的套接字,并向该套接字中写入相应的信息;套接字的状态改为正在连接;

服务器端也是发送一个TCP头部给客户端(操作与客户端的操作相同,但是有些地方的设置要反过来,比如TCP头部的源IP与目的IP、源端口与目的端口之类);此外,还要将ACK位置为1,表示已经接收到相应的网络包。
>
< 客户端接收到数据,经以太层、IP层解析之后到达TCP层;
TCP层通过接收到的TCP头部的SYN位确认连接服务器的操作是否成功;若SYN位为1,(表示连接成功),此时TCP模块会向套接字中写入服务器的IP地址,端口号等信息;并将套接字的状态设置为连接完毕;
同样地,客户端也需要将TCP头部的ACK位置1并将TCP头部传给IP层并委托IP层发送给服务器端。
服务器收到客户端第二次发送的网络包,连接操作全部完成。

此后,套接字进入了随时可以收发数据的状态。到这里,也就是connect执行完毕。

收发数据

请求消息进入协议栈

协议栈收到数据后,先将其存放在内部的发送缓冲区,继续等待应用程序后续的数据;协议栈是否发送数据有以下两个判断要素:

  • 缓存的数据包长度是否接近MSS(最大分段大小)。MSS=MTU-ip_head_len-tcp_head_len,MTU(最大传输单元)一般为1500;
  • 等待时间。即使数据包长度还未接近MSS,但是已经等待了一定时间,为避免造成发送延迟,也会将数据包发送出去;

应用程序可以控制数据包发送的时机(长度优先或时间优先),若应用程序未指定,则由协议栈自行决定。

对长数据进行拆分

当应用程序送入协议栈的数据长度大于MSS,数据以MSS个字节为单位进行分组,在每组数据前加上TCP头部后送入IP层,委托IP将数据发送。

 

 

网络包的接收确认

每发送一个网络包,都需要进行确认操作。首先,在客户端(发送方)与服务器端(接收方)建立连接时,客户端(发送方)向服务器(接收方)发送的tcp头部使用一个32位的随机数作为序列号;在(发送方)TCP模块拆分数据时,每一数据块前所加的TCP头部的序列号为在上述序列号(32位的随机数)的基础上加上数据块的位置。服务器端(接收方)在收到网络包后,会计算ACK值(序列号+data_len+1);

 

服务器端(接收方)创建一个TCP头部(ACK的值为上述ACK的值,ACK位置1),然后发送给客户端(发送方);客户端(发送方)在没有收到某个数据包对应的ACK号之前,数据包会一直保存在发送缓冲区中,如果没有收到某个数据包对应的ACK号,TCP模块会重新发送此数据包。

以下是TCP数据包传输的示意图(简便起见,没有考虑32随机数的初始序列号)。

 

 

同时,TCP的数据收发是双向的,即服务器端作为发送方、客户端作为接收方,也会为网络包的接收确认做上述操作。

如下是TCP数据双向传输的示意图:

 

 

ACK号等待时间

TCP协议采用动态调整的策略来设置ACK号的等待时间。策略是:在TCP模块发送数据时持续测量ACK号的等待时间,若ACK号的返回变慢,则增大ACK号的等待时间,若ACK号的返回变快,则减小ACK号的等待时间。

滑动窗口

接收方告知发送方自己最多能接收的数据,然后发送方根据这个值对发送的数据量进行控制。以下是一个TCP滑动窗口的示例。

 

ACK与窗口信息的合并发送

Q1:接收方何时要向发送方发送窗口的更新信息?

答:应用程序从接收缓冲区取出数据后。

Q2:接收方何时要向发送方发送ACK号?

答:收到数据包确认无误后。

为了提高网络的效率,可考虑将这两种信息放入同一tcp头部进行发送。这时,在等待过程中(一种情形是刚刚收到了tcp数据包并确认无误,等待应用程序从接收缓冲区取出数据;另一种情形是应用程序从接收缓冲区取出了数据,等待数据包的到来与确认),窗口信息或ACK号会有多个值,此时只需要传递最终结果即可。