Skip to the content.

网络

扩展阅读

图解 QUIC 连接

常见问题

沾包问题

TCP 协议在底层机制上解决了 UDP 协议的顺序问题和重传问题, 但是相比 UDP 又带来了新的问题, TCP 是流式的, 数据包没有边界, 应用程序使用 TCP 通信就会面临这些问题. 因为 TCP 是流式的, 在接收一个大数据包时, 可能会拆分为多个数据包进行发送, 多次 Send 底层也可能会合并成一次进行发送, 这里会使用下面两个操作来解决:

  1. 分包: Server 收到了多个数据包, 需要拆分数据包
  2. 合包: Server 收到的数据包只是一部分, 需要缓存数据, 合并成完整的包.

那么针对这两种情况, 我们需要一些解决方案:

  1. EOF 结束符协议
  2. 固定包头 + 包体协议 (包长度, json格式, html格式等)

TCP 特性

  1. TCP 提供一个 面向连接, 可靠的 字节流服务
  2. 只支持单对单通信, 不支持多播和广播
  3. TCP 使用校验和, 确认和重传机制来保证可靠传输
  4. TCP 给数据字节进行排序, 并使用积累确认保证数据的顺序不变和不重复
  5. TCP 使用滑动窗口机制实现流量控制, 通过动态改变窗口大小进行阻塞控制

(4) tcp的握手与挥手, 握手能否两次? 能否四次? 挥手为什么是4次? 三次会怎么样? (需要了解状态变化)

三次握手 (创建连接) (Three-way Handshake)

三次握手是指建立一个 TCP 连接时, 客户端和服务端一共要发送3个包

  1. 第一次握手 (SYN=1, seq=x)

    服务端监听某个端口时就会处于 LISTEN 状态. 客户端发送一个 TCP 的 SYN 标志位置1的包, 指明客户端打算连接的服务器的端口, 以及初始化序号 X, 保存在包头的序列号 (Sequence Number) 字段里. 发送完毕后, 客户端进入 SYN_SEND 状态

  2. 第二次握手 (SYN=1, seq=y, ACK=1, ACKnum=x+1)

    服务器发回确认包(ACK)应答.即 SYN 标志位和 ACK 标志位均为1. 服务器端选择自己 ISN 序列号, 放到 Seq 域里, 同时将确认序列 (Acknowledgement Number) 设置为客户端的 ISN+1, 即 x+1. 发送完毕后, 服务器端进入 SYN_RECD 状态

  3. 第三次握手 (ACK=1, ACKnum=y+1)

    客户端再次发送确认包 (ACK), SYN 标志位为0, ACK标志位为1, 并且把服务器发来 ACK 的序列号字段 + 1, 放在确认字段中发送给对方, 并且在数据库放 ISN的+1 发送完毕后, 客户端进入 ESTABLISHED 状态, 当服务器端接收到这个包时, 也进入 ESTABLISHED 状态.

四次挥手 (断开链接) (Four-way handshake)

TCP 的连接的断开需要发送四个包. 服务端和客户端均可以主动发起挥手动作. 在 socket 编程中, 任意一方执行 close() 方法操作即可产生挥手操作.

  1. 第一次挥手 (FIN=1, seq=x)

    假设客户端想要关闭连接, 客户端发送一个 FIN 标志位置为1的的, 表示自己已经没有数据可以发送了, 但是仍可以接收数据.

    发送完毕后, 客户端进入 FIN_WAIT_1 状态.

  2. 第二次挥手 (ACK=1, ACKnum=x+1)

    服务器端确认客户端的 FIN 包, 发送一个确认包, 表明自己已经收到了客户端断开连接的请求, 但是还没有准备好关闭连接.

    发送完毕后, 服务器端进入 CLOSE_WAIT 状态, 客户端接收到确认包后进入 FIN_WAIT_2 状态, 等待服务器关闭连接

  3. 第三次挥手 (FIN=1, seq=y)

    服务器端准备好关闭连接时, 向客户端发送结束连接请求, FIN 置为 1

    发送完毕后, 服务器端进入 LAST_ACK 状态, 等待客户端的最后一个 ACK

  4. 第四次挥手 (ACK=1, ACKnum=y+1)

    客户端接收到来自服务器端的关闭请求, 发送一个确认包, 并进入 TIME_WAIT 状态, 等待可能出现的要求重传的 ACK 包.

    服务器端接收到这个确认包后, 关闭连接, 进入 CLOSED 状态.

    客户端等待了某个固定时间 (两个最大段生命周期, 2MSL, 2 Maximum Segment Lifetime)之后, 没有收到服务器端的 ACK, 认为服务器 已经正常关闭连接, 于是自己也关闭连接, 进入 CLOSED 状态.

为什么要四次挥手

为双方好

  1. 保证接收端收到了 ACK 信息进入 CLOSED 状态
  2. 如果立即进入 CLOSED 状态, 且正好有连接使用的四元组件相同, 就会导致新的连接接收到旧连接的数据包. 总的来说就是让旧连接数据包消失在网络传输中.

连接队列

TCP 延迟确认

TCP 会采用延迟确认的策略减少性能开销. 当接收到数据后会稍微等待下看有没有数据包需要发送, 如果有数据包返回就会顺带一起进行 ACK 确认, 当然若等待过程中没有数据包传输最后也会单独进行 ACK 确认, 这就是延迟确认.

(3) TCP 通过什么来保证可靠传输的?

  1. 确认和重传: 接收方收到报文就会确认, 发送方发送一段时间后没有收到确认就重传.
  2. 数据较远
  3. 数据合理分片和排序(接收方会缓存未按照顺序到达的数据, 重新排序后再交给应用层)
  4. 流量控制: 当接收方来不及处理发送方的数据, 能提示发送方降低发送的速率, 防止包丢失
  5. 阻塞控制: 当网络阻塞时, 减少数据的发送

(4) TCP与UDP区别, 分别在哪一层

都在运输层, 使用网络层的 IP 协议提供动力

TCP 阻塞控制怎么实现?

拥塞: 是指数据发送速度超出网络所能承受的极限, 经常造成路由器丢包的现象

拥塞窗口cwnd(congestion window)

慢开始门限ssthresh状态变量

ssthresh的用法如下:

通过阻塞窗口实现的, 包含几种常见方法:

  1. 慢开始 (1开始, **增加, (拥塞控制: 到达上限速度变为++))

    TCP 开始发送报文时段先设置 cwnd = 1, 然后再逐渐增大 (*2 增加)

    发送方维持阻塞窗口, 阻塞窗口的大小取决于网络的阻塞程度, 是动态变化的.

    发送方让自己的发送窗口等于阻塞窗口, 另外考虑到接收方的接收能力, 发送窗口可能小于阻塞窗口

    慢开始的思路是, 不要一开始就发送大量数据, 先探测一下网络的阻塞程度, 也就是说由小到大逐渐增加阻塞窗口的大小

  2. 拥塞避免 (乘法减小, 加法增大)

    让拥塞窗口缓慢增长, 每经过一个往返时间 RTT 就把发送方的阻塞窗口 cwnd++, 而不是加倍, 这样阻塞窗口按线性规律缓慢增长

    拥塞窗口大于慢开始门限, 就执行拥塞避免算法

  3. 快重传

    发送方只要一连收到三个重复的确认时就应当重传对方尚未收到的报文. 而不必等到该分组的重传计时器到期.

  4. 快恢复 (门限上线减半, 然后从这一半开始++)

    当发送方连续收到三个重复确认时, 就执行 “乘法减少” 算法, 吧 ssthresh 门减半, 但是接下去并不执行慢开始算法

    考虑到如果网络出现拥塞的话就不会收到好几个重复的确认, 所以发送方现在认为网络可能没有出现拥塞. 所以此时不执行慢开始算法, 而是将 cwnd 设置为 ssthresh 减半后的值, 然后执行拥塞避免算法, 使 cwnd 缓慢增大

(3) TCP 传输过程中如何做流量控制? 扩大窗口和缩小窗口机制?

是指让发送方的发送速率不要太快, 让接收方来得及接收

主要思路是让发送方知道接收方当前的接收能力, 调整发送速率

当接收方告知还有空余缓存空间时, 发送方将扩大窗口, 反之减小窗口

原因

双方在通信的时候, 发送方和接收方的速率不一定是相等的, 如果发送方的速率太快, 会导致接收方处理不过来, 这个时候接收方只能够把处理不过来的数据放到 缓存区中, 如果缓存区满了发送方还在疯狂发送数据, 接收方只能把接收到的数据包丢掉, 极大的浪费网络资源, 所以需要控制发送方的发送速率, 让接收方 和发送方处于一种平衡状态才好, 对于发送方发送速率的控制, 称为流量控制.

控制方法

接收方每次接收到数据包, 可以在发送确定报文的时候, 同时告诉对方自己缓存区还剩多少是空闲的, 我们也把缓存区的剩余大小叫做接收窗口的大小, 用变量win表示

发送方收到之后, 会调整额自己的发送速率, 也就是调整自己发送窗口的大小, 当发送方收到窗口大小为0时, 发送方就会停止发送数据, 防止出现大量丢包情况的发生.

当接收方收到 接收窗口 win = 0 时, 这时发送方停止发送报文, 并且同时开启一个定时器, 每隔一段时间就发个测试报文去询问接收方, 看是否可以继续发送 数据, 如果可以, 接收方就告诉他此时接收窗口的大小. 如果接收窗口大小还是0, 则接收方再次刷新启动定时器.

窗口越大越好吗?

现在的 TCP 协议中窗口大小是不固定的, 如果接收窗口过小, 会严重浪费链路利用率, 增加丢包率. 当接收窗口到达某个值的时候, 再增大也不怎么会减少 丢包率了, 而且会更加消耗内存, 所以接收窗口的大小必须根据网络环境以及发送发的拥塞窗口来动态调整.

TCP 头信息

UDP 头信息

UDP 最小长度: 无数据情况下, 仅首部8字节 UDP 数据部分最小 0 字节 UDP 最大长度, 受长度字段16位的限制, 所以最大长度为 2**16 - 1 = 65535 字节 UDP 数据部分最大长度: UPD 最大长度 - IP 最小头部 - UDP 头部 = 2**16 - 20 -8 = 65507 字节

IP 头信息是否了解

实际上指的是 TCP/IP 协议中的数据报结构

IP, TCP, UDP 头部之间的关系

IP 头部在网络层组装和解析

TCP, UDP 头部在运输层组装和解析

SYN 攻击 (DDos攻击)

什么是 SYN 攻击

在三次握手的过程中, 服务器发送 SYN_ACK 之后, 收到客户端 ACK 之前的TCP连接称为 半连接状态 (half open connect). 此时服务器处于 SYN_RECD 状态, 需要客户端回复 ACK 才能进入 ESTABLISHED 状态.

SYN 攻击指的是, 攻击客户端在短时间内伪造出很多不存在的 IP 地址, 向服务器不断的发送 SYN 包, 服务器回复确认包, 并等待客户端的确认. 由于这些 IP 是不存在的, 服务器需要不断的重复发送直至超时, 这些伪造的 SYN 包将长时间占用未连接队列. 正常的 SYN 请求被丢弃, 导致系统运行缓慢, 严重的会导致 网络阻塞甚至系统瘫痪.

SYN 攻击是一种典型的 Dos/DDoS 攻击

如何检测 SYN 攻击

检测 SYN 攻击非常方便, 当你在服务器上看到大量的半连接状态时, 特别是 IP 地址是随机的, 基本上可以断定这是一次 SYN 攻击. 在 Linux/Unix 上 可以使用系统自带的 netstats 来检测 SYN 攻击.

netstat -n -p -t | grep SYN_RECV | grep :80 | wc -l

如何防御 SYN 攻击?

SYN 攻击不能完全被阻止, 除非将 TCP 协议重新设计. 我们所做的是尽可能减轻 SYN 攻击的危害, 常见的防御 SYN 攻击的方法有:

keepalive 有什么用?

TCP 的连接, 实际上是一种纯软件层面的概念, 在物理层面并没有 “连接” 这种概念. TCP 通信双方建立交互的连接, 但是并不是一直存在数据交互, 有些连接会在数据交互完毕后, 主动释放连接, 而有些不会. 在长时间无数据交互的这段时间内, 双方都可能会出现掉电, 死机, 异常重启等各种意外, 当这些意外发生之后, 这些 TCP 连接并未来得及正常释放, 在软件层面上, 连接的另一方并不知道对端的情况, 它会一直维护这个长连接, 长时间的积累 会导致非常多的半打开连接, 造成端系统资源的消耗和浪费, 为了解决这个问题, 在传输层可以利用 TCP 的KeepAlive 机制实现来实现.

TCP KeepAlive 的基本原理是, 隔一段时间给连接对方发送一个探测包, 如果收到对方回应的 ACK, 则认为连接还是存活的, 在超过一定重试次数之后 还是没有收到对方的回应, 则丢弃该 TCP 连接.

局限性:

  1. TCP KeepAlive 检测的方式是发送一个 prbe 包, 会给网络带来额外的流量.
  2. 只能在内核层级检测连接的存活与否, 连接存活并不代表服务一定可用. 所以 TCP KeepAlive 对于应用层程序的价值相对较小, 一般程序会在应用层 自己实现自己的心跳功能.

TCP在哪一层? OSI 五层分别是什么? 各层功能是什么? 都有哪些协议?

TCP在运输层

close_wait 太多怎么处理? 为什么会出现这种情况? (Too many open files)

原因

四次挥手中, 服务端在第二次挥手进入 CLOSE_WAIT 状态后, 没有进一步发送 FIN 包给客户端, 导致服务端大量 CLOSE_WAIT 状态的 TCP 连接等待着. 服务端(被动关闭方)没有及时的发送第二个 FIN 包呆滞的 一般来说, 是程序代码本身出了问题, 导致连接无法走完整的四次握手断开.

主子进程共享 socket, close 不能完全关闭

UDP使用场景(计算机系统中使用UDP),在什么情况下优先考虑使用UDP。

  1. 网络通讯质量要求不高
  2. 要求网络通讯速度尽可能快

举例: QQ语音, QQ视频 (允许丢帧, 但是不容易接受重发导致的画面声音延迟)

TCP 使用场景

  1. 对网络通信质量要求高

举例: 发送邮件, 浏览网页, SSH 连接, QQ 文件传输

如何使用 UDP 实现 TCP ?

实现 TCP 实际上就是指用 UDP 实现 TCP 的几个特性:

  1. 确认: 接收方收到包后会回复确认
  2. 超时重传: 超过时间后没有收到确认会发送重传
  3. 数据包排序: 对数据包进行排序
  4. 缓存区: 对未接受完整的数据包, 放入缓存区, 等待接收完整后拼装给应用层
  5. 流量控制和拥塞控制: 使用头信息实现滑动窗口, 用来流量控制和拥塞控制

如何可靠化 UDP ?

  1. 确认重传机制
  2. 发送包有递增序号, 接收方发现中间丢包就要发重传请求
  3. 网络太差时要有发送窗口限制(流量控制)
  4. 接收方缓存区慢了要有停发机制

tcp发送数据时, 服务器宕机了会怎么样? 然后服务器又好了又会怎么样?

客户端会收不到 TCP 的确认包, 然后会尝试重传, 对应的有流量拥塞控制机制, 会逐渐减少发包量.

当达到设置的重试次数后, 将断开链接.

close_wait, time_wait

close_wait 在四次挥手的第一次接收方产生, 表明接收方接收到了请求方的关闭连接的请求, 但还没有准备好关闭连接. time_wait 在四次挥手的最后一次产生, 发送方在最后确认包发生后, 将进入 2MSL 的等待期, 在没有收到服务器端的 ACK, 认为接收方 已经正常的关闭连接了, 于是自己也关闭连接, 进入 CLOSED 状态

(2) select 和 epoll 的区别, epoll 如何实现不轮询?

都是 IO 多路复用机制. IO 多路复用就通过一种机制, 监听多个描述符, 一旦某一个描述符就绪(一般是读或者写就绪), 就能够通知程序进行相应的操作.

Socket 是什么

socket 是对 TCP/IP 协议族的一种封装, 从设计模式来讲, 就是一个门面模式. Socket 起源于 Unix, 可以看做是一种特殊的文件.

select 工作机制? 针对进程还是线程?

针对进程的, select 的核心是一组文件 fd(简称fds), 如果fds中的某个fd的状态符合要求(比如变得可读可写等, 或者有异常等等), select 就从 等待中返回.

(4) http 与 https 的区别, 加密怎么加的? (ca证书作用)

超文本传输协议, 超文本安全传输协议, 都在应用层, 基于 TCP 协议.

SSL 作用

SSL 协议是一种网络安全协议, 它在传输通信协议(TCP/IP)上实现的一种安全协议, 采用公开秘钥技术

(3) http 各种返回码, 401 和 406 的区别?

一个 10M 大小的 buffer 里存满了数据, 现在要把这个 buffer 里的数据尽量发送出去, 可以允许部分丢包, 请问用 tcp 好 还是 udp 好? 为什么?

使用 UDP 可以保证速度, 没有重传机制, 没有阻塞机制, 保证最快速度

使用 TCP 可以保证尽量不丢包, 丢包会重传, 在网络环境差的情况下推荐使用

一个完整的 Http 请求会涉及到哪些协议?

应用层: HTTP 运输层: TCP 网络层: IP 数据链路层: ARP (地址解析协议), RARP (逆地址解析协议)

(2) POST GET HEAD 区别

一次http连接成功后断开重新及进行第二次http连接, 是否需要重新tcp连接?

主要看 http 连接时有没有使用 HTTP keep-alive, 如果使用了的话, 不会重新建立 tcp 连接.

lnmp 网站请求过程中做了什么?

  1. DNS 解析, 将域名解析成 IP
  2. tcp 连接
  3. 发起 HTTP 请求
  4. 请求到达 Nginx 处理
  5. Nginx worker 处理, 转发给 fast-cgi 模块处理
  6. 通过 fastcgi_pass 转发给 php-fpm 处理
  7. php-fpm master 指派 worker 进程进行请求处理, 如果没有可用进程, 则返回 502
    • ZendVM 处理阶段
      • 词法语法分析, 生成 AST
      • 解析 AST, 生成 zend_op_array
      • ZendVM 执行 zend_op_array
  8. worker 处理请求, 如果超时, 则返回 504
  9. 请求处理结束, 返回结果给 nginx

HTTP 1.0, HTTP 1.1, HTTP 2.0

从一台 server 访问另一台 server 出现 unreachable 报错如何排查网络那个部分出现错误。

csrf 原理

跨站点请求伪造(Cross-site request forgery), 是一种网络攻击方式.

CSRF 攻击利用网站对于用户网页浏览器的信任, 挟持用户的一登录身份, 去执行非用户本意的操作

WebSocket 内容? 属于那一层? 基于什么实现的?

网络协议的一种, 应用层, 是 HTTP 协议的一种补充

访问百度的过程中, 各层做了什么

浏览页面过程中, client和server做了什么?

Accept 发生在TCP三次握手的哪个阶段? connect, listen 函数?

服务器端: socket->bind->listen->accept

客户端: socket->connect

accept 发生在三次握手后, 客户端和服务器建立了 tcp 连接, 这时可以调用 accept 函数获得此连接

基于 UDP 的应用层协议有什么? 基于 TCP 的有什么?

503 状态码怎么解决

服务器处于维护或者过载状况, 这个状况是暂时的, 并且将在一定时间后恢复. 如果能够预计延迟时间, 可以在 Retry-After 表明这个延迟时间. 如果没有 标明这个时间, 那么可以当做 500 处理.

快重传的作用

快重传是 TCP 拥塞算法中的一条, 当连续收到三条同一个报文的确认回复后, 发送端可以直接对下一个包进行重试发送. 而不用等重传计时器到期.

http 缓存机制有哪些? 什么是CDN? header中涉及到缓存的字段有哪些?

由于 HTTP 协议是无状态的协议, 所以服务端需要记住用户的状态时, 就会使用 Session 来保存用户数据.

Session 是保存在服务端的, 保存方式有多种: 文件, 数据库, 缓存, 内存都有.

会产生 Session ID 储存在客户端中, Cookie 会在客户端请求服务端时, 被附带在头信息上, 这样服务端可以获取到这一部分的信息, 包括 Session ID, 就可以查询到对应的 Session , 区分出用户的数据

html 页面, 怎么与后端交互? 流程是什么? 涉及到哪些组件?

put, post 实现有什么优缺点?

前后端分不分离有什么区别? 有什么优缺点?

前后端只通过 JSON 来交流, 组件化, 工程化不需要依赖后端去实现.

前端: 只负责 View 和 Controller 层 后端: 只负责 Model 层, 业务处理/数据等

常见web攻击有哪些? csrf 攻击了解吗?

restful 的作用? 有哪些优点和缺点?

restful 是一种风格,

  1. 状态无关 —— 确保系统的横向拓展能力
  2. 超文本驱动,Fielding的原话是”hypertext-driven” —— 确保系统的演化能力
  3. 对 resource 相关的模型建立统一的原语,例如:uri、http的method定义等 —— 确保系统能够接纳多样而又标准的客户端

nginx 达到上限了怎么办? 怎么对 nginx 负载均衡? dns ?

  1. 做 nginx 集群
  2. DNS 均衡负载, 请求分发到不同的 nginx 主机地址上

拥塞控制的算法有哪几种?慢开始前期是指数型增长还是线性增长?

websocket能做负载均衡么?

可以使用 nginx 来做均衡负载

nginx为什么性能很高

接收方的读缓冲区为0,当读缓冲区读完的时候,发送方如何知道该发送了?

发送端会在接收方反馈缓存区慢时, 设置一个定时器, 定时查询接收方有多少缓冲区, 来判断是否可以发送数据了

websocket 是怎么实现服务器往客户端推送消息的?

TCP 建立的全双工通信通道

Http 协议为什么不支持推送?

HTTP 2.0 支持主动推动

不支持推送是由于协议规定的, HTTP 定义了一 request 一 response 的操作, 所以不能够主动推送

TCP 协议是一个双工协议, 也就是说: 基于 TCP 的服务器都具有主动推送的功能, 但是 HTTP 协议自身定义的规则不允许推送

select poll epoll 比较

epoll 水平触发和边缘触发

epoll 使用的数据结构

epoll 高效的本质

LVS 和 Nginx 分别作用在 osi 哪一层?

LVS 只作用于运输层

Nginx 可以作用于运输层, 还可以作用于应用层

负载均衡算法

在不同的网络层上, 可以做不同的均衡负载

网络不可达排查流程

TCP 关闭连接

TCP 最多有几个连接 (fd, 四元组ip port 限制)

Client:

每个 TCP 连接占用一个文件描述符(端口), 本地最大端口数量为 65536 个, 端口0有特殊作用, 故最多能创建 65535 个 TCP 连接.

Server:

Server 启动后端口占用固定, 故最大 TCP 连接数等于 客户端ip数量 * 客户端port数量 2^48 个

长连接基于 TCP 怎么实现的

TCP 握手后使用完不断开连接, 后续发包复用该连接.

维持连接:

TCP 层 KeepAlive 参数. 应用层订单发送心跳包.

UDP 与 TCP 可以同时监听一个端口吗?为什么

可以

sockaddr 结构包含 协议, IP, 端口. 由于协议的不同, 同一个端口下可以区分监听的是 TCP 还是 UDP

QUIC 协议

是一种快速 UDP 互联网连接协议,是由 google 提出的使用 udp 进行多路并发传输的协议。

相对于现在比较广泛的 http2 + tcp + tls 协议有以下优势:

  1. 减少了 TCP 三次握手以及 TLS 握手时间。
  2. 改进的拥塞控制。
  3. 避免队头阻塞的多路复用 TCP 协议的序列号导致的。
  4. 连接迁移
  5. 向前冗余纠错

  6. 连接建立时延低

TCP 三次握手需要 1.5RTT建立连接 TLS 握手需要 3RTT 而 QUIC 由于建立在 UDP 基础上,还实现了 0RTT的安全握手,所以在大部分情况下,只需要 0 RTT 就能实现数据发送。

  1. 改进的拥塞控制

TCP 包含四个算法: 慢启动,拥塞避免,快速重传,快速恢复

而 QUIC 协议默认使用当前 TCP 协议的 Cubic 拥塞控制算法, 同时还支持多种拥塞控制算法。

特色在于:

场景:

  1. 提升连接建立速度
  2. 优化弱网环境下的使用体验
  3. 优化网络频繁切换下的使用体验
  4. 需要根据不同场景切换拥塞控制算法时