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中状态
- 左下角虚线方框中是主动关闭方关闭时会经历的状态转移