面向字节流

流字可以体现出报文与报文之间是粘到一块的,没有间隔

创建一个TCP的socket,同时在内核中创建一个发送缓冲区和一个接收缓冲区(在操作系统中)

  • 调用write时, 数据会先写入发送缓冲区中;
  • 如果发送的字节数太长, 会被拆分成多个TCP的数据包发出;
  • 如果发送的字节数太短, 就会先在缓冲区里等待, 等到缓冲区长度差不多了, 或者其他合适的时机发送出去;
  • 接收数据的时候, 数据也是从网卡驱动程序到达内核的接收缓冲区;
  • 然后应用程序可以调用read从接收缓冲区拿数据;
  • 另一方面, TCP的一个连接, 既有发送缓冲区, 也有接收缓冲区, 那么对于这一个连接, 既可以读数据, 也可 以写数据. 这个概念叫做 全双工

由于缓冲区的存在,TCP程序的读和写不需要一一匹配,例如:

  • 写100个字节数据时, 可以调用一次write写100个字节, 也可以调用100次write, 每次写一个字节
  • 读100个字节数据时, 也完全不需要考虑写的时候是怎么写的, 既可以一次read 100个字节, 也可以一次 read一个字节, 重复100次;

粘包问题(存在于应用层)

  • 首先要明确, 粘包问题中的 “包” , 是指的应用层的数据包;
  • 在TCP的协议头中, 没有如同UDP一样的 “报文长度” 这样的字段, 但是有一个序号这样的字段.
  • 站在传输层的角度, TCP是一个一个报文过来的. 按照序号排好序放在缓冲区中.
  • 站在应用层的角度, 看到的只是一串连续的字节数据
  • 那么应用程序看到了这么一连串的字节数据, 就不知道从哪个部分开始到哪个部分, 是一个完整的应用层 数据包.

那如何避免粘包问题呢?归根结底一句话,明确两个包之间的边界

思考:对于UDP协议来说,是否存在“粘包问题”呢?

  • 在UDP协议中不会存在粘包问题
  • 对于UDP, 如果还没有上层交付数据, UDP的报文长度仍然在. 同时, UDP是一个一个把数据交付给应用 层. 就有很明确的数据边界
  • 站在应用层的站在应用层的角度, 使用UDP的时候, 要么收到完整的UDP报文, 要么不收. 不会出现"半 个"的情况

TCP是怎么保证可靠性的?

  • 去重
  • 面向连接
  • 按序到达:多条报文同时发,收到顺序不一定一致,TCP考虑到这一点,即按序到达,给报文排序,即使2先导弹,那也先执行1。
  • 确认应答
  • 校验和
  • 流量控制

TCP是怎么提高效率的?

  • 滑动窗口
  • 快重传
  • 捎带应答
  • 延迟应答

如何做到报头与有效载荷的分离?

有4位TCP报头长度,剩下的都是载荷

为什么不把序号和确认序号放在一起?

因为TCP是全双工的,可以同时发送同时接收

TCP/UDP对比

我们说了TCP是可靠连接, 那么是不是TCP一定就优于UDP呢? TCP和UDP之间的优点和缺点, 不能简单, 绝对的进行 比较

  • TCP用于可靠传输的情况, 应用于文件传输, 重要状态更新等场景;
  • UDP用于对高速传输和实时性要求较高的通信领域, 例如, 早期的QQ, 视频传输等. 另外UDP可以用于广播;

用UDP实现可靠传输(经典面试题)

参考TCP可靠性机制,在应用层实现类似的逻辑
例如:

  • 引入序列号,保证数据顺序
  • 引入确认应答,确保对端收到了数据
  • 引入超时重传,如果隔一段时间没有应答,就重发数据
  • 引入流量控制…