共计 2586 个字符,预计需要花费 7 分钟才能阅读完成。
CS 架构与对等实体
CS 位置
备注
特点
举例
同一机器
数据会被环回,并不会放到网络设备输出队列中
几乎没有网络延迟和丢包
自己开发 web 程序调试
同一局域网内
极少没有网络延迟和丢包
打印机
不同网络
位于广域网
途径的路由器如果队列空间耗尽,就会导致丢弃分组,进而导致重传。重传又会引起分组的重复和乱序。
真实环境
基本套接字 API 回顾
SOCKET socket (int domain, int type, int protocol)
// 成功返回套接字描述符,失败时返回 -1
套接字 API 与协议无关。
domain 是个常量,表示通信域,有以下两个
AF_INET 用于因特网
AF_LOCAL 用于同一台机器上的 IPC 通信,即进程间通信
type 说明套接字的类型,有常见的以下几种
SOCK_STREAM 提供可靠,全双工,面向连接的字节流,例如 TCP
SOCK_DGRAM 提供不可靠,尽力而为的数据服务,例如 UDP
SOCK_RAW 允许对 IP 层的某些数据进行访问,例如监听 ICMP 报文
protocol 说明使用哪种协议,对 tcp/ip 来说,可以直接由 type 字段隐式说明,参数被设置为 0
int connect (SOCKET s, const struct socketaddr *peer, int peer_len)
// 成功时返回 0,失败时返回非 0
s: 套接字描述符
peer: 是一个地址结构,存储对等实体的地址和其他信息
peer_len;是地址结构的长度
connect 一旦建立起来,就可以传输数据。在 unix 中,套接字描述符可以像文件描述符那样调用 read 和 write。但是 windows
int recv (SOCKET s, void *buf, size_t len, int flags)
int rend (SOCKET s, cosnt void *buf, size_t len, int flags)
参数 s, buf, len 和 read, write 参数一样。flags 通常和系统有关。unix 和 win 都支持以下 flag
MSG_OOB 收发紧急数据
MSG_PEEK 查看输入数据,但是不从缓冲区删除数据。俗称瞥一眼
MSG_DONTROUTE 绕过通常的选路函数,通常只有选路函数使用,或用于诊断
理解面向连接和无连接协议的区别
面向连接和无连接,指的都是协议,不是物理介质,是指数据在介质上如何传输
本质区别是,对于无连接协议,每个分组的处理都是独立的。对于面向连接的协议,分组还要维护后续分组的相关信息。
无连接协议是面向连接协议的基础
无连接协议就像是寄信,每封信都有自己的收件人地址,你可以同时给多个人寄信。邮局处理信件也不会管每封信之间的关系。
面向连接的协议就像是打电话,一个人先拨号,等另一个人说喂,然后自己在说我是某某某。说完话了,一个人会说,拜拜,另一个也会说拜拜。有时候你听不清楚对方在说什么,还会说:麻烦你在说一遍,我没听清。或者:你说的太快了,麻烦说慢一点。
——–
应用程序
——–
TCP 和 UDP
——–
IP
——–
物理接口
——–
TCP 的每个分组成为段(segment), 是放在 IP 数据包中发送的。但是 IP 数据报并不保证数据的可靠到达。所以 TCP 必须自己实现可靠性。
TCP 使用三个功能实现可靠性
校验和:校验和用来校验数据有没有被中途损坏,保证安全性
序列号:每个段都有自己的序号,用来重新排列乱序的段,保证顺序性
确认重传机制: 保证每个段都被对方收到,保证可靠性
TCP 的三个功能中,确认重传机制最为复杂。
TCP 接收窗口
左边箭头表示窗口的左边界,所期望下一个字节的序列号
右边箭头表示窗口的右边界,表示 TCP 缓冲区所能容纳字节的最大编号,用来防止缓冲区溢出
TCP 到达时,所有序列号在窗口范围之外的,都会被直接丢弃
如果段中的第一个字节序号是期望的字节号,就通知应用程序有数据可读。并且将窗口向右滑动
TCP 发送窗口
发送窗口分为两个部分,已经发送出的但是还没有收到确认的,还有可以发送但还没有发送的
在 4 - 7 字节已经发送出去之后,TCP 会启动一个 RTO(retransmission timeout) 超时重传定时器,如果定时器超时之前这四个字节没有被确认,就会重传这四个字节。要注意重传的自己可以要比四个字节要多。
重传并不意味着数据没有到达目的地,也有可能是 ACK 丢失
TCP 是一种流协议
TCP 是一种流协议,并没有固定的报文和报文流的概念。
发送两次报文并不发送两个独立的实体,两次调用 send, 只是将数据交给底层 TCP/IP 栈。至于底层是如何发送这两个数据的,由底层自己决定。
底层将数据发出去有很多决定因素
发送窗口
拥塞窗口
路径最大传输单元
输出队列中有多少数据
不要低估 TCP 的性能
TCP 并不是绝对可靠
故障模式
对等实体崩溃
网络中断
不要把 OSI 七层模型太当回事
实际上 OSI 模型由很多缺点,本质上说 OSI 协议已经停用了。OSI 模型是理想,TCP/IP 才是现实。
理解 TCP 写操作
从应用程序角度看,send
从 TCP 角度看,慢启动,ng 算法
TIME-WAIT
通常,只有主动关闭连接的一方会进入 TIME-WAIT 阶段
RFC 793 将 MSL 定义为两分钟,那么 2MSL 就是 4 分钟。实际的操作系统可以将 MSL 设置为更低的值,如 30 秒。
如果连接处于 TIME-WAIT 阶段,又有分组到达,就会重启 2MSL 定时器。
使用 TIME-WAIT 的目的
维护连接状态,以防主动发起连接关闭的哪一方最后一个 ACK 丢失造成另一端发送 FIN
耗尽网络中所有此连接的走失提供时间
想一想,如果主机 1 在发出 ACK 之后立即关闭了连接,会发生什么事?
AB 分别为主机
有 TIME-WAIT 状态时,如果 ACK 丢失,那么 B 会重发 FIN, A 处于 TIME_WAIT 阶段时,再次收到 FIN, 那么就会再次发送 ACK, 并重启激动 2MSL 计时。
无 TIME-WAIT 状态时, 主机 A 的收到 FIN 后,立即释放端口,那么该端口处于未监听状态。当数据被发送到为监听的端口时,发送方会收到链接重置的报文。
无 TIME-WAIT 状态时, 主机 A 的端口已经被新的应用程序占用,新的连接的数据可能被迟来的数据破坏。
TCP 的状态转移图
TCP 一共有 11 中状态
左下角虚线方框中是主动关闭方关闭时会经历的状态转移
尽可能写入一个大块数据,而不是频繁的写入小块的数据
参考书籍
TCP/IP 高效编程
TCP/IP 详解 卷 1:协议
UNIX 网络编程 卷 1:套接字联网 API(第 3 版)