网络编程实战
盛延敏
前大众点评云平台首席架构师
立即订阅
6034 人已学习
课程目录
已完结 39 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 学好网络编程,需要掌握哪些核心问题?
免费
第一模块:基础篇 (9讲)
01 | 追古溯源:TCP/IP和Linux是如何改变世界的?
02 | 网络编程模型:认识客户端-服务器网络模型的基本概念
03丨套接字和地址:像电话和电话号码一样理解它们
04 | TCP三次握手:怎么使用套接字格式建立连接?
05 | 使用套接字进行读写:开始交流吧
06 | 嗨,别忘了UDP这个小兄弟
07 | What? 还有本地套接字?
08 | 工欲善其事必先利其器:学会使用各种工具
09丨答疑篇:学习网络编程前,需要准备哪些东西?
第二模块:提高篇 (10讲)
10 | TIME_WAIT:隐藏在细节下的魔鬼
11 | 优雅地关闭还是粗暴地关闭 ?
12 | 连接无效:使用Keep-Alive还是应用心跳来检测?
13 | 小数据包应对之策:理解TCP协议中的动态数据传输
14丨UDP也可以是“已连接”?
15 | 怎么老是出现“地址已经被使用”?
16 | 如何理解TCP的“流”?
17 | TCP并不总是“可靠”的?
18 | 防人之心不可无:检查数据的有效性
19丨提高篇答疑:如何理解TCP四次挥手?
期中复习周 (2讲)
期中大作业丨动手编写一个自己的程序吧!
免费
期中大作业丨题目以及解答剖析
免费
第三模块:性能篇 (12讲)
20 | 大名⿍⿍的select:看我如何同时感知多个I/O事件
21 | poll:另一种I/O多路复用
22 | 非阻塞I/O:提升性能的加速器
23 | Linux利器:epoll的前世今生
24 | C10K问题:高并发模型设计
25 | 使用阻塞I/O和进程模型:最传统的方式
26 | 使用阻塞I/O和线程模型:换一种轻量的方式
27 | I/O多路复用遇上线程:使用poll单线程处理所有I/O事件
28 | I/O多路复用进阶:子线程使用poll处理连接I/O事件
29 | 渐入佳境:使用epoll和多线程模型
30 | 真正的大杀器:异步I/O探索
31丨性能篇答疑:epoll源码深度剖析
第四模块:实战篇 (4讲)
32 | 自己动手写高性能HTTP服务器(一):设计和思路
33 | 自己动手写高性能HTTP服务器(二):I/O模型和多线程模型实现
34 | 自己动手写高性能HTTP服务器(三):TCP字节流处理和HTTP协议实现
35 | 答疑:编写高性能网络编程框架时,都需要注意哪些问题?
结束语 (1讲)
结束语丨我相信这不是结束,让我们江湖再见
网络编程实战
登录|注册

13 | 小数据包应对之策:理解TCP协议中的动态数据传输

盛延敏 2019-08-30
你好,我是盛延敏,这里是网络编程实战第 13 讲,欢迎回来。
在上一篇文章里,我在应用程序中模拟了 TCP Keep-Alive 机制,完成 TCP 心跳检测,达到发现不活跃连接的目的。在这一讲里,我们将从 TCP 角度看待数据流的发送和接收。
如果你学过计算机网络的话,那么对于发送窗口、接收窗口、拥塞窗口等名词肯定不会陌生,它们各自解决的是什么问题,又是如何解决的?在今天的文章里,我希望能从一个更加通俗易懂的角度进行剖析。

调用数据发送接口以后……

在前面的内容中,我们已经熟悉如何通过套接字发送数据,比如使用 write 或者 send 方法来进行数据流的发送。
我们已经知道,调用这些接口并不意味着数据被真正发送到网络上,其实,这些数据只是从应用程序中被拷贝到了系统内核的套接字缓冲区中,或者说是发送缓冲区中,等待协议栈的处理。至于这些数据是什么时候被发送出去的,对应用程序来说,是无法预知的。对这件事情真正负责的,是运行于操作系统内核的 TCP 协议栈实现模块。

流量控制和生产者 - 消费者模型

我们可以把理想中的 TCP 协议可以想象成一队运输货物的货车,运送的货物就是 TCP 数据包,这些货车将数据包从发送端运送到接收端,就这样不断周而复始。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《网络编程实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(20)

  • d
    就拥塞控制算法这块,记得前一阵阿里发布一个HPCC算法,盛老师点评一下?谢谢

    作者回复: 哈哈,研究性质的算法,应该还不错吧,不知道什么时候可以实际使用

    2019-08-30
    5
  • 张立华
    非阻塞socket,对于write和send, 返回实际发送的字节数。所以一般在while里不断发送,直到全部发送完毕。 send根据只要根据要发送的buf做个偏移,很方便。 而writev 就很繁琐了啊

    作者回复: 你说的不错,一般我们只在合并缓冲区的时候才需要,绝大多数都是使用write和send 。

    2019-08-30
    3
  • _CountingStars
    问题1 : grep 'IOV_MAX' /usr/include/limits.h

    作者回复: 赞

    2019-09-18
    2
  • 衬衫的价格是19美元
    拥塞控制算法的话,应该是bbr吧,已经被合入linux  4.9内核了。与传统的reno, cubic等策略相比,最大的不同是,bbr不会因为链路噪声而执行乘性减窗,导致延迟过大。实际上,目前gwf的随机丢包的策略也是链路噪声。

    作者回复: Google出品,名声不小。

    2019-10-04
    1
  • Donkey
    请教老师一个愚钝问题:大数据循环发送时,那接收方怎么接收才能接收完整的包?不会发生粘包等现象呢?

    作者回复: 我觉得这个问题不愚钝。

    每个包都有一个序列号,通过序列号按顺序就可以还原这个数据流;这个数据流本身也有例如checksum,序号大小等数据,这个数据流所有序列号的包都收到了,就可以完成数据流的拼装了。

    解决粘包问题的关键是区分出数据的边界,我在第16降:如何理解TCP的“流”里讲到了这部分内容,你可以参考一下。

    2019-09-18
    1
    1
  • LDxy
    下载软件通常使用多线程建立多个TCP连接来下载一个大文件,是不是也是为了尽量避免TCP拥塞控制带来的影响,从而充分利用带宽?因为从实际使用来看,下载软件一旦跑满带宽,其他软件基本是是抢不过它的

    作者回复: 这是为了加速下载的时间,说白了就是抢带宽。

    2019-08-30
    1
  • 许童童
    TCP 拥塞控制算法,我知道最新的有BBR算法,这个算法在网络包填满路由器缓冲区之前就触发流量控制,而不在丢包后才触发,有效的降低了延迟。

    作者回复: 嗯,我也是刚知道这个算法。

    2019-08-30
    1
  • 咸鱼强
    客户端代码的第30行 变量n 好像并没有用到?

    作者回复: 是的,本来想打印出这个n的。

    2019-12-06
  • godtrue
    概念较多,不过举个例子就好理解了,比如:在北京和华盛顿之间有一条可以双向传输货物的传送带,计算机的一切都是为了更快的速度和更大的容量,底层的实现更是如此,再对照各种概念就好理解了,他们所做的一切就是为了更有效地利用网络带宽。
    需要权衡的就是,发多少信息?啥时候发?收发之间怎么实现无缝衔接,都没有无谓的等待,各种设备都满负荷的运转。
    2019-11-23
  • 码农Kevin亮
    请问老师,文中提到的小数据包发送的场景二三都是基于同一个目的地的吧?不同目的地的数据包不管多小,也不能合并发送吧?

    作者回复: 是的,基于同一个目的地址。这里是说为了提高网络利用率,不能无限制的发送小数据包,也就是说,多个小数据包会在合适的时机合并成一个大的数据包发送出去。你的理解是相反的?

    2019-11-17
  • 夏目
    老师,我有个问题,你举的那个例子里面,取发送窗口和拥塞窗口最小值的80,缓冲区数据是100不能发送出去。那么这个缓冲区数据要什么时候才能发送出去呢,是等到发送缓冲区大于100吗?发送窗口是上一次的ack返回时发送端拿到的吗?那发送端怎么知道什么时候大于100的呢?

    作者回复: 需要等到发现窗口和拥塞窗口都要超过100才可以,发送窗口是在ACK返回时根据一定的算法更新的,一旦更新就会影响发送端的行为。

    2019-11-04
  • JasonZhi
    老师你好,有个问题想求证一下,对文件执行write 操作时会经过缓冲区,缓冲区满了才执行磁盘操作。而对socket 执行write 操作,虽然也会经过缓冲区,但是并不一定需要等到缓冲区满了才发送。不知我的理解是否正确?

    作者回复: 确实是两路不同的实现,但是我不理解为什么文件写需要缓冲区满才进行呢?应该会合并写入,但是不一定需要缓冲区满吧。

    2019-09-25
  • CCC
    「客户端分两次将一个请求发送出去」,这种情况我在本地模拟只看到了当数据包比MSS大的时候TCP才会拆包发送,请问老师还有别的情况会让一个请求多次发送出去吗?还有就是这种拆包发送有可能拆成两个小数据包(小于MSS)吗?

    作者回复: 我个人觉得不会,应该是拆分成MSS大小的包,否则会浪费带宽。

    2019-09-19
  • 徐凯
    老师 最后提到的那个问题 那些网络库会不会在内部做处理 就像是运行库函数内部还有缓存的原理一样

    作者回复: 当然有的。

    2019-09-03
  • yusuf
    1)、iov_len的总和<=32767, iovcnt <= 16
    2019-09-02
  • yusuf
    场景二中,发送端把接下来连续的几个小数据包存储起来,等待接收到前一个小数据包的 ACK 分组之后,再将数据一次性发送出去。

    是将多个数据包合并成了1个包吗?

    作者回复: 是的。

    2019-09-01
    3
  • 谢童
    老师,writev 是原子操作吗?在多线程的情况下可以不加锁使用吗?

    作者回复: 不是原子操作,不过建议还是单线程来处理一个socket,因为加锁的读写操作太重了。

    2019-08-31
  • 不动声色满心澎湃
    writev是减少write的使用次数吧。一次writev中的数据也有可能分多个包发出去。我说的对吗老师

    作者回复: 当然,我们决定不了发包的次数。只不过合并写的方式,让操作系统可以一次性发送出去的几率更大。

    2019-08-31
  • 请教老师一个问题,慢启动是因为需要探测网络带宽质量,快恢复,快重连是什么意思呢?

    作者回复: TCP在收到乱序到达包会立即发送ACK,TCP利用3个相同的ACK来判定数据包的丢失,进行快速重传,以便让对方能在较短的时间内接受到丢失的包,本质上是一种通过"弥补"机制保证拥塞控制能完成。

    2019-08-30
    1
  • 问题一:Linux中最多允许1024个元素
    请教一个问题,tcp中有各种窗口,很头晕,比如,发送窗口,接收窗口,通告窗口(Advertised window),滑动窗口,拥塞窗口。为什么要弄这么多窗口呢?都是为了做流量控制吗?如何去理解呢?

    作者回复: 发送窗口和接收窗口都是通过滑动窗口机制来实现的,这是为了流量控制而引入的概念;而拥塞窗口则是为了拥塞控制而引入的概念。

    2019-08-30
    1
收起评论
20
返回
顶部