面向字节流
流字可以体现出报文与报文之间是粘到一块的,没有间隔
创建一个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可靠性机制,在应用层实现类似的逻辑
例如:
- 引入序列号,保证数据顺序
- 引入确认应答,确保对端收到了数据
- 引入超时重传,如果隔一段时间没有应答,就重发数据
- 引入流量控制…