「网络」TCP/IP与MAC

  • TCP定义

    1. TCP 是一个可靠的, 面向连接的, 基于字节流的, 全双工协议

    2. 面向连接的: 先建立逻辑连接, 再发送数据

    3. 可靠的: 超时重传, 流量控制, 拥塞控制

    4. 基于字节流: 没有固定报文边界

    5. 全双工: 发送接收并行

  • TCP/IP分层

    1. 具体分层

      1. 应用层: HTTP, FTP, SMTP, DNS, POP3

      2. 传输层: TCP, UDP; 信息单元为段

      3. 网络互联层(网络层): IP, ICMP, ARP

      4. 网络访问层(链路层): IEEE 802.11(无线); 信息单元为帧

    2. 最大传输单元(MTU)与最大段大小(MSS)

      1. 链路层传输的帧有大小限制, 帧的数据部分的最大长度称为最大传输单元(MTU); IP协议会按照MTU切分数据报, 每个IP数据报头部有个表示"分片偏移"的字段, 用于表示该分段在原始数据报中的位置

      2. TCP为避免被IP协议切分, 会主动自己切割, 即最大段大小(MSS) = MTU-IP头大小-TCP头大小, TCP有一个socket选项TCP_MAXSEG可以设置本次链接的MSS

      3. 以太网数据包负载为1500字节, TCP负载一般为1450字节

    3. 一个TCP连接可由四元组唯一确定: 本地IP地址, 本地端口, 远程IP地址, 远程端口

  • TCP头部

    1. 由"源端口 + 目标端口 + 序列号 + ack确认号 + TCP标记位 + 窗口大小"构成

    2. 端口号

      1. 有端口, 没有IP是因为网间传递不归传输层管理. 传输层用端口号区分同一主机上不同程序, 80为HTTP, 443为HTTPS, 22为ssh

      2. 熟知端口号0-1023, 已登记端口号1024-49151, 临时端口号49152-65535

      3. socket的SO_REUSEADDR选项, 允许端口重用

    3. ack确认号: 1) 告知对方下一个期望接收的序列号 2) 小于此确认号的报文均已接收

    4. TCP flags有8位, 这些标记可以组合使用(置为1), 常见的组合有: SYN+ACK, FIN+ACK; SYN: 建立连接, ACK: 接收确认, RST: 强制断开连接, FIN: 断开连接, PSH: 不缓存

      1. RST用来异常的关闭连接

        1. 发送RST时, 不必等缓冲区的数据都发送出去, 而是直接丢弃, 连接进入CLOSED状态

        2. 接收RST后, 不需要ACK确认, 连接立即进入CLOSED状态

        3. RST出现情况: 端口未监听/服务端关闭/服务端奔溃时, 收到客户端连接, 会返回RST(Connection Reset或者Connection refused)

        4. Broken pipe与Connection reset by peer错误很常见, 出现前提都是连接已关闭. 其中Broken pipe出现时机是: 在一个 RST的套接字继续写数据, 就会出现Broken pipe

    5. 窗口大小, 16位 (最大允许2^16字节, 即64KB)

    6. TCP状态

      1. 三次握手时: closed状态(客户端/服务器), listen状态(服务器), syn_sent状态(客户端), syn_rcvd状态(服务器), established状态(客户端/服务器)

      2. 四次挥手时: established状态(客户端/服务器), fin_wait1状态(客户端), close_wait状态(服务器), fin_wait2状态(客户端), last_ack状态(服务器), time_wait状态(客户端), closed状态(客户端/服务器)

  • TCP三次握手

    1. 三次握手目的是建立连接,并交换初始序列号, 最大段大小, 窗口大小

    2. 为什么SYN报文不携带数据却要消耗一个序列号?

      凡是消耗序列号的TCP报文段, 一定需要对端确认, 如果未收到对端确认, 会不停重传. TCP中不占用序列号的报文, 是不需要确认的, 比如ACK包

    3. 为什么要三次握手, 而不是两次

      防止是客户端先前的请求, 导致服务器建立了连接, 故需要客户端再次确认.

    4. time_wait状态过多

      1. 表现

        客户端无法建立新的链接

      2. 原因

        客户端短时间内建立了大量短连接, 连接断开后, TCP正在经历time_wait状态

      3. 解决

        1. 短连接变为长连接

        2. 参数配置, SO_REUSEADDR??

  • TCP四次挥手

    1. 一般都是客户端主动挥手, 但服务器奔溃, 重启时, 也会主动发起挥手. 重新启动服务器会存在"Address already in use"的情况, 原因是服务器进入了TIME_WAIT状态, 需要保留连接2MSL(最大报文生存时间, 1个MSL大约2分钟). 客户端为什么不存在这种情况, 因为客户端端口一般都是临时的, 每次很难重合

    2. 为啥要有TIME_WAIT状态(挥手后, 客户端为何要等一段时间再关闭)

      1. 确保旧连接时的报文在链路中不存在

      2. 避免最后一个ACK, 被动关闭方没收到, 导致重发FIN时无人回应, 从而保证TCP全双工的连接可靠终止

    3. 为什么TIME_WAIT状态是两个MSL

      1. 一个MSL确保最后一个ACK能到达对端

      2. 一个MSL确保对端没收到ACK而重传的FIN能到达

  • TCP滑动窗口 (发送端到接收端的流量控制)

    1. TCP会把要发送的数据放入发送缓冲区, 接收到的数据放入接收缓冲区, 应用程序会不停读取接收缓冲区的内容进行处理

    2. 为控制发送端的流量速率, 接收端会告知发送端自己的接收窗口, 也就是接收缓冲区中空闲的部分. 发送端滑动窗口机制允许在收到确认前, 在发送窗口的限制下发送多个包

    3. 接收窗口: 接收端概念, 接收缓冲区中空闲的部分, ACK包里会带着自己接收窗口的大小, 对端会根据该大小调整发送策略

      发送窗口: 发送端概念, 一端在某时刻能拥有最大未确认数据包大小, 包括已用窗口+可用窗口, 发送窗口需要小于接收窗口

      1. 已用窗口: 发送端概念, 已发送但未收到确认的数据包

      2. 可用窗口: 发送端概念, 未发送但接收端有空间接收的数据包

    4. 发送窗口变为0了怎么办: 零窗口探测包 (就是ACK包, seq为当前连接seq-1), 发送方不断向接收端发送该ACK包

      利用零窗口探测机制的攻击, 从服务器下载大文件, 接收一部分后接收窗口置为0, 服务器开始长达十几分钟的零窗口探测机制, 多个连接并发压榨服务器资源

  • TCP拥塞处理 (整个网络的流量控制)

    1. 拥塞窗口与滑动窗口都是控制发送端速率, 滑动窗口保证接收端能力, 拥塞窗口保证网络能力

    2. 拥塞窗口: 收到对端ACK之前, 自己还能发送的MSS段数

    3. 拥塞窗口的大小在发送端本地内存中, 不会被交换

    4. 发送端真正发送窗口的大小(某刻最大未确认数据包大小) = min(发送端自己拥塞窗口的大小, 接收端反馈的接收窗口的大小)

    5. 慢启动: 拥塞窗口初始值很小, 收到一个ACK后, 窗口值增加1, 经过一个RTT后, 窗口值变为原来的两倍.

      • RTT (往返时延), 发送端发送数据, 到发送端收到对端确认(对端立即确认)所经历的时间

      • 拥塞窗口初始值为系统中的变量initcwnd, 为10, 大约16KB. (90%的HTTP请求为16KB, 即10个MSS. 因此慢启动对于大文件传输会有时延)

    6. 快速重传/选择确认

      1. 传统的重传需要等几百毫秒, 为了减少等待, 引入了"快速重传"与"选择确认"机制

      2. 快速重传: 收到一个未按序到达的数据段时, 接收端回复上次的ACK, 当发送端收到3个重复ACK时, 立即重传, 而不必等到重传超时器超时再重传. (上次的ACK即等于最大的连续包号)

        ack表示这之前的包已经收到了, 四个包: (1: 1001), (1001: 2001), (2001, 3001), (3001, 4001); 第二个未收到, 即使第三/四个收到了, 服务端也只能回复1001, 表示seq为1001之前的数据包已经都收到了, 当服务器收到客户端重传的第二个包后, 立即回复ACK为4001, 表示seq为4001之前的数据包均已收到.

      3. 选择确认(SACK): 如何让发送端知道需要重传哪个包. ACK 1001, SACK=1:1001 2001:5001, 表示接收端收到最大连续包号为1001, 额外[1:1001] [2001:5001]的包也已收到. 发送端明白只要重传[1001:2000]即可

    7. 快速恢复, 发送端收到三次重复ACK时, 进入快速恢复, 即网络轻度拥塞. 拥塞阈值降为拥塞窗口的一半, 拥塞窗口设置为拥塞阈值

  • TCP延迟确认

    1. 收到数据包后暂时没有数据给对端, 可以等一段时间再确认(Linux上是40ms). 有数据要给对端, ACK一并发出. 再次收到对端数据, 则合并ACK. 没有数据要发送但已过一段时间, 也发送ACK, 避免对端认为丢包.

    2. 除了收到乱序包立即ACK, 其余均延迟确认

  • TCP半关闭/半连接/半打开

    1. TCP半关闭

      向对端发送FIN, 对端也回应了ACK, 但对端没有回应FIN给我, 此时我就处于半关闭状态, 可以接收数据, 但不能发送数据

    2. TCP半连接

      服务器发送SYN+ACK, 客户端还未回应ACK, 服务器处于半连接

    3. TCP半打开

      • 已建立连接, 但一方突然断开(断电, 断网), 另一方仍会维持连接的建立. 如果一直没有通信, 该问题会无法察觉

      • 解决方法是TCP提供了keepalive机制, 该机制在2小时没有数据包交互后会发送keepalive探测包, 但这个等待时间太长, 遂一般应用都未开启, 而是自己实现心跳机制.

      • keep-alive与keepalive区别: HTTP的keep-alive是保持长连接, 即多个HTTP可依次使用一个TCP, TCP的keepalive用于心跳检测

  • IP头部

    1. IP报文头中有一个存活时间字段TTL, 表示一个IP报文最大可经过路由数, 每经过一个路由器, TTL减1, 当TTL减到0, 该IP报文会被丢弃

    2. 源IP地址, 目标IP地址

    3. 偏移量: IP将根据各分片的偏移量重组包

    4. 协议类型: TCP/UDP

    5. 混淆概念: MSL(TCP报文最大生存时间), Linux中一般为30秒, MSL比TTL的时间还会大些

  • MAC头部

    1. 源MAC地址, 目标MAC地址. MAC地址用处就是就是将包送达下个路由器

    2. 以太类型: IP, ARP

  • MAC

    1. ARP协议: 广播这个IP是谁的, 目标设备会返回MAC地址

    2. 将包发送到接收方的整体过程是由IP控制的(由路由器操控), 而将包转发到下一个路由器的过程是由以太网控制的(由交换机操控). 整个通讯过程中数据包的IP头部不会变, 而MAC头部会变

    3. 路由器相当于是网卡, 有IP地址和MAC地址, 交换机则没有IP地址和MAC地址. 路由器只接受数据包MAC头部中接收方MAC地址为自己的包, 交换机会接收所有的包

    4. 路由器内部有路由表, 路由表有目标地址, 网关. 路由器收到包后, 检查该包MAC头部中接收方MAC地址是否为自己, 是自己则丢弃MAC头部, 并在路由表中根据该包的接收方IP地址按序检查表中目标地址, 从而找到网关, 如果找到的网关为空, 则该包已到达最终设备, 否则该网关就是下一个路由器的IP地址, 之后通过ARP协议获得网关对应的MAC地址, 封装为新的MAC头部

    5. 交换机内部有MAC地址与网线端口映射表, 收到包后, 将MAC头部中发送方MAC地址与接收端口更新到映射表中, 之后通过查表, 找到目标MAC地址相应的端口转发出去

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值