您当前的位置: 首页 > 

恐龙弟旺仔

暂无认证

  • 0浏览

    0关注

    282博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

TCP滑动窗口模拟实战

恐龙弟旺仔 发布时间:2022-06-18 09:04:39 ,浏览量:0

1.TCP滑动窗口机制

客户端与服务端之间的通信是一个数据传输的过程,消息以数据包形式进行传输。

在传输的过程中,通过滑动窗口机制来同时传输多个数据包;发送端根据接收端的处理能力,适当控制发送窗口大小,实现流量控制。

1.1 数据包单独发送

在数据包较大的情况下,需要将大的数据包拆分成多个小的数据包进行传输。

接收端确认接收到一个数据包之后,发送端才能发送下一个数据包。整个过程如下图所示:

很明显,这种方式方式的数据传输效率非常低,发送端只有等到接收端确认收到之后才能发送下一个数据包。

为了改进这种情况,引入了窗口的概念。

1.2 数据包窗口批量发送

窗口大小是指:不需要等待确认包而可以继续发送的数据包的最大值

在以下的示例中,我们假定窗口大小为3。整个过程如下所示:

 

从上图中可知:发送端在发送1-1000数据包之后,并没有等待接收端返回确认包,就开始发送1001-2000和2001-3000数据包。

通过这种方式,就可以省去多个数据包的数据传输时间。

1.3 数据包窗口流量控制

在使用窗口批量发送时,发送方需要根据接收方的处理能力在实时调整发送窗口大小。

当接收方没有多余空间再接收数据时,发送方调整窗口大小为0(如果发送方不调整,则接收方则会丢弃到接收到的数据包),依此来实现TCP流量控制。

我们假定接收方窗口大小默认为5,在传输的过程中,窗口大小有调整,整个过程如下:

 

在接收端窗口调整后,发送方则最多一次只能发送窗口大小的数据。

通过一组图来展示下整个窗口滑动过程:

 

在三次握手之后,发送端了解到接收端窗口大小为5。

第一次发送数据为3000个字节

 

接收端接收到3000个字节后,返回ACK确认收到。

此时由于某些原因调整窗口大小为3

 

发送端接收到第一次ACK后,窗口向前滑动,开始发送4000 5000两个数据包

发送端接收到调整后的窗口大小后,滑动窗口大小调整为3

 

接收端确认接收到4000 5000两个数据包,接收窗口此时又调整为5 

同样,发送端接收到ACK包后,窗口前移,开始发送6000 7000两个数据包 

总结:通过一组图来展示下发送端与接收端整个处理过程。

发送端的可发送窗口大小即为接收端可用窗口大小

2.wireshark抓包窗口变化过程

笔者通过一个示例,来展示下接收端的窗口变化。

正常情况下,接收方在接收到请求数据包之后,立即处理掉,那么可接收窗口大小就又恢复到原来大小。

笔者在这里为了模拟窗口变化,使接收方在接收到请求数据包之后,不再处理,此时发送方依旧每秒发送10KB数据。

代码及抓包结果如下

2.1 发送方及接收方代码

2.1.1 发送方代码

public class ClientTest {
    public static void main(String[] args) throws Exception {
        byte[] one_kb = new byte[10 * 1024];
        byte a = 'a';
        Arrays.fill(one_kb, a);

        Socket client = new Socket("127.0.0.1", 10000);
        OutputStream outputStream = client.getOutputStream();

        for (int i = 0; i < 1000; i++) {
            try {
                outputStream.write(one_kb);
                outputStream.flush();
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

 2.1.2 接收方代码

public class SocketTest {

    public static void main(String[] args) throws Exception {
        ServerSocket server = new ServerSocket(10000, 5);
        int acceptCount = 0;
        while (true) {
            Socket client = server.accept();
            System.out.println("new connection has connected, num=" + acceptCount++);
            // 连接成功后,不处理该连接的任何请求
        }

    }
}
2.2 wireshark抓包

2.2.1 三次握手

发送方与接收方在三次握手时交换窗口大小

接收方Win=65535 发送方Win=2619648

2.2.2 数据发送过程中的窗口变化

第一次发送后 133行,接收方返回窗口大小为2609408,该窗口大小为(初始窗口大小[2619648]-接收数据大小[10240]=2609408)

同理,第一次发送后 152行,接收方返回窗口大小为,该窗口大小为2599168(上次窗口大小[2609408]-接收数据大小[10240]=2599168)

同理,第一次发送后 154行,接收方返回窗口大小为2609408,该窗口大小为(初始窗口大小[2599168]-接收数据大小[10240]=2588928)

2.2.3 最终接收方消耗完所有的窗口缓存

 

最终,接收方Win=0 (1322行),此时发送方再发送任何数据都无法被接收。

而且,此时发送方的发送窗口大小也等于0,此时便不再发送数据。

参考:

TCP滑动窗口机制深度剖析

Linux-TCP之深刻浅出send和recv - JavaShuo

 

关注
打赏
1655041699
查看更多评论
立即登录/注册

微信扫码登录

0.0425s