Linux网络编程系列-TCP传输控制
滑动窗口(sliding window)
滑动窗口是用于流量控制的,发送端根据接收端的处理能力发送数据,不至于造成过多的丢包。 是发送方和接收方间的协调,对方的接收窗口大小就是自己的发送窗口大小。
在TCP头中有一个字段window,这个字段就是接收端告诉发送端自己还有多少缓冲区可以接收数据。发送端根据这个字段的值来发送数据,当值为0时就停止发送。
发送端和接收端各自维护着一个窗口,发送的滑动窗口控制可以发送的数据大小,接收端的窗口控制可以接收数据的大小。
发送端:LastByteAcked指向已经被成功接收的位置,LastByteSent指向最后已发送出去的位置,usable window表示发送端还可以发送的数据大小。如上图,发送端还有5个单位数据还未被ack,还可以再发送7个单位的数据。
接收端:LastByteExpected指向接收端收到的连续包的最后一个位置,LastByteRcvd指向收到的包的最后一个位置,waited come表示期望收到的包序列,waited read表示在缓冲区中还未读走的数据,usable window表示缓冲区还能接受的大小。如上图,缓冲区还能接受7个单位的数据,就会把7赋值给tcp头中的window字段。
发送端当收到window为0时,就停止发送数据,会陆续发送3次ZWP(zero window probe)询问接收端是否有可用窗口,接收端会回复可用窗口,如果3次都为0,发送端可能中断链接。
拥塞控制
滑动窗口用于流量控制,避免发送超过接收端处理能力的数据,导致数据丢失,是两端之间的协调。
拥塞控制是TCP用于发送端和网络情况间的协调,和慢启动一起避免恶化网络状况。根据网络延时情况,确定可发送窗口大小。这就抽象出一个拥塞窗口(congestion window)的概念,其最大值是发送窗口大小。
TCP有四个算法来动态调节拥塞窗口(cwnd)大小:
慢启动
连接建立时,cwnd=1
cwnd线性上升,每收到一个ACK,cwnd++
cwnd指数上升,每过一个RTT(round trip time),cwnd = cwnd * 2拥塞避免
当cwnd>=ssthresh(slow start threshold),进入拥塞避免,cwnd的增加算法改成如下:
每收到一个ack,cwnd=cwnd + 1/cwnd,基本不增加
每过一个RTT,cwnd=cwnd + 1,在一个往返时间内最多为 cwnd增加 1 个报文段拥塞发生(超时RTO,丢包-重复收到同一个包的ACK)
ssthresh = cwnd/2
cwnd = 1,发送端基本不发送数据了。开始了慢启动的过程。快速恢复
TCP为保证数据达到有两种重传算法,超时重传和快速重传。超时重传是等待RTT时间没收到ack,则重传;快速重传是接收端配合,接收端每收到一个tcp segment,返回的都是收到的连续序列的下一个序号,发送端收到3次同样的序号就进行重传。
快速恢复通常和快速重传一起使用,如果接收端还能收到重复的ACK,说明收发两端还有数据流动。所以没必要反映那么强烈,不需要把cwnd降为1,可以缓和点减少流量,不进入慢启动。这是快速恢复的思想。
1) 当收到第 3 个重复的 ACK时(认为拥塞发生),将 ssthresh设置为当前拥塞窗口 cwnd的一半。重传丢失的报文段。设置cwnd为ssthresh加上3倍的报文段大小。
2) 每次收到另一个重复的 ACK时, cwnd增加 1个报文段大小并发送 1 个分组(如果新的cwnd允许发送)。
3) 当下一个确认新数据的ACK到达时,设置 cwnd为ssthresh(在第1步中设置的值)。这个ACK应该是在进行重传后的一个往返时间内对步骤 1 中重传的确认。另外,这个ACK也应该是对丢失的分组和收到的第 1 个重复的 ACK之间的所有中间报文段的确认。这一步采用的是拥塞避免,因为当分组丢失时我们将当前的速率减半。
总结下,收到重复的ack时,窗口和阈值减半,进入拥塞避免,试探性的重发丢失的报文段,直到无窗口可用或者拥塞消除。
注:网络实际传输受slidingwnd和cwnd控制,TCP能传输的最大数据 = MIN(slidingwnd, cwnd)
参考TCP的那些事儿(下)http://coolshell.cn/articles/11609.html
Linux网络编程系列-TCP传输控制的更多相关文章
- linux网络编程系列-TCP/IP模型
### OSI:open system interconnection ### 开放系统互联网模型是由ISO国际标准化组织定义的网络分层模型,共七层 1. 物理层:物理定义了所有电子及物理设备的规范, ...
- Linux网络编程系列-TCP编程实例
实例: client #include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #inc ...
- 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系
[Linux网络编程]TCP网络编程中connect().listen()和accept()三者之间的关系 基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: conn ...
- 【Linux 网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系
基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: connect()函数:对于客户端的 connect() 函数,该函数的功能为客户端主动连接服务器,建立连接是通过三 ...
- Linux网络编程系列-套接口选项控制
获取和设置套接口选项的方法有: getsockopt/setsockopt fcntl ioctl getsockopt/setsockopt 这两个函数仅用于套接口(socket)的设置,另外两个函 ...
- linux网络编程笔记——TCP
1.TCP和UDP TCP是长连接像持续的打电话,UDP是短消息更像是发短信.TCP需要消耗相对较多的资源,但是传输质量有保障,UDP本身是不会考虑传输质量的问题. 2.网络传输内容 我习惯的做法是直 ...
- Linux网络编程学习(二) ----- 进程控制(第三章)
1.进程和程序 程序是一个可执行文件,而一个进程是一个执行中的程序实例.一个进程对应于一个程序的执行,进程是动态的,程序是静态的,多个进程可以并发执行同一个程序.比如几个用户可以同时运行一个编辑程序, ...
- Linux 网络编程系列教程
一.基础理论篇 01.网络协议入门 02.LAN.WAN.WLAN.VLAN 和 VPN 的区别 03.IP 地址介绍 04.广播地址介绍 05.无连接和面向连接协议的区别 06.因特网的IP协议是不 ...
- linux网络编程之断点传输文件
以下载链接"http://www.boa.org/boa-0.94.13.tar.gz"为例: 断点续传实验大概步骤: ===================== 1,使用geth ...
随机推荐
- python:threading多线程模块-创建线程
创建线程的两种方法: 1,直接调用threading.Thread来构造thread对象,Thread的参数如下: class threading.Thread(group=None, target= ...
- 用nexus搭建maven私服
首先介绍一下背景,公司访问外网有限制,项目组大部分人员不能访问maven的central repository,因此在局域网里找一台有外网权限的机器,搭建nexus私服,然后开发人员连到这台私服上 环 ...
- 再牛逼的梦想,也抵不住SB似的坚持
说起梦想,哪都是好几年前的事了.自从毕业之后,梦想不知道去哪了.可能一次次的失败,找不到了梦想的方向了吧! 自从毕业去了深圳,为了能够在这个城市安稳下来,白天正常上班晚上在街上摆地摊给人下载音乐和电影 ...
- Android Service完全解析,关于服务你所需知道的一切(下)
转载请注册出处:http://blog.csdn.net/guolin_blog/article/details/9797169 在上一篇文章中,我们学习了Android Service相关的许多重要 ...
- js中replace的回调函数使用。
这只是一个小问题,但是之前并没有发现.这个问题就是replace的第二个函数是支持回调函数的. var ext = new RegExp('f','g'); 1.str.replace(ext ,1) ...
- ApiDoc 文档使用方式
1.安装node.js 2.打开node.js 命令窗(shell)键入npm install apidoc -g 自动安装(几分钟) 3. C:\Users\user\AppData\Roaming ...
- UI基础之UITextField相关
UITextField *textF = [[UITextField alloc] init]; 1.字体相关 textF.text = @"文本框文字"; textF.textC ...
- C语言小练习三
题目要求: 定义一个二维数组保存 10个学生的5门课成绩,分别用函数实现:(1)input():输入每个学生的成绩:(2)output():输出每个学生的成绩:(3)aver_stu():计算并输出每 ...
- ES6详解
1.ES6新增了let命令,用来声明变量.它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效. const声明常亮,不可改变 2.变量的解构赋值 (1)数组的解构赋值: 以前,为 ...
- Spring中获取数据库表主键序列
在程序开发中,我们经常有写数据库表的操作,数据表中经常带有主键自增序列,如何获取自增序列.spring中提供了相应的类 DataFieldMaxValueIncrementer. DataFieldM ...