1 TCP简介

  CP的全称是Transmission Control Protocol,即传输控制协议,TCP工作在传输层上

  其职责是:实现主机间进程到进程的通信,其次还需要保证可靠性(不是安全性,换言之不能保证安全性)

2 特点

  1)点对点:一个发送方,一个接收方

  2)可靠:可靠的、按序的字节流

  3)流水线机制:

    TCP拥塞控制和流量控制机制  
    设置窗口尺寸
  4)发送方/接收方缓存
  5)全双工:同一连接中能够传输双向数据流
  6)面向连接
    通信双方在发送数据之前必须建立连接
    连接状态只在连接的两端中维护,在沿途节点中并不维护状态
    TCP连接包括:两台主机上的缓存、连接状态变量、socket等
 

3 TCP的可靠

  TCP会尽自己所能,尽量将数据发送给对方;但并不能保证100%可以发送给对方
  TCP会在数据发送不到对方的情况下,会给应用层一个错误提示,告知用户发送失败
  TCP可以保证接收方(应用层)严格按照发送时的数据顺序接收
  TCP保证数据不会出现无意间的损坏(UDP 也做到这点)
  TCP尽可能地维护网络质量

4 TCP报文格式

4.1 端口号

  源端口号:报文的发送端口

  目的端口号:报文的就收端口

4.2 序号(seq)

  序号(Sequence Number):TCP传输过程中,在发送端出的字节流中,传输报文中的数据部分的每一个字节都有它的编号。

  序号(Sequence Number)的语义与SYN控制标志(ControlBits)的值有关。根据控制标志(Control Bits)中的SYN是否为1,序号(SequenceNumber)表达不同的含义:

    当SYN = 1时,当前为连接建立阶段,此时的序号为初始序号ISN((Initial Sequence Number),通过算法来随机生成序号;

    当SYN = 0时在数据传输正式开始时,第一个报文的序号为 ISN +1,后面的报文的序号,为前一个报文的SN值+TCP报文的净荷字节数(不包含TCP头)。

    比如,如果发送端发送的一个TCP帧的净荷为12byte,序号为5,则发送端接着发送的下一个数据包的时候,序号的值应该设置为5+12=17。

4.3 确认序号ACK(AcknowledgmentNumber)

  标识了报文接收端期望接收的字节序列。如果设置了ACK控制位,确认序号的值表示一个准备接收的包的序列码,注意,它所指向的是准备接收的包,也就是下一个期望接收的包的序列码。

4.4  控制标志位

  控制标志(Control Bits)共6个bit位,具体的标志位为:URG、ACK、PSH、RST、SYN、FIN。6个标志位的说明,如下面所示。
  URG 占1位,表示紧急指针字段有效。URG位指示报文段里的上层实体(数据)标记为“紧急”数据。当URG=1时,其后的紧急指针指示紧急数据在当前数据段中的位置(相对于当前序列号的字节偏移量),TCP接收方必须通知上层实体。
  ACK 占1位,置位ACK=1表示确认号字段有效;TCP协议规定,接建立后所有发送的报文的ACK必须为1;当ACK=0时,表示该数据段不包含确认信息。当ACK=1时,表示该报文段包括一个对已被成功接收报文段的确认序号Acknowledgment Number,该序号同时也是下一个报文的预期序号。
  PSH 占1位,表示当前报文需要请求推(push)操作;当PSH=1时,接收方在收到数据后立即将数据交给上层,而不是直到整个缓冲区满。
  RST 占1位,置位RST=1表示复位TCP连接;用于重置一个已经混乱的连接,也可用于拒绝一个无效的数据段或者拒绝一个连接请求。如果数据段被设置了RST位,说明报文发送方有问题发生。
  SYN 占1位,在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文。对方若同意建立连接,则应在响应报文中使SYN=1和ACK=1。 综合一下,SYN置1就表示这是一个连接请求或连接接受报文。
  FIN 占1位,用于在释放TCP连接时,标识发送方比特流结束,用来释放一个连接。当 FIN = 1时,表明此报文的发送方的数据已经发送完毕,并要求释放连接。
  在连接建立的三次握手过程中,若只是单个SYN置位,表示的只是建立连接请求。如果SYN和ACK同时置位为1,表示的建立连接之后的响应.

4.5 窗口大小

  长度为16位,共2个字节。此字段用来进行流量控制。流量控制的单位为字节数,这个值是本端期望一次接收的字节数。

4.6 检验和

  长度为16位,共2个字节。对整个TCP报文段,即TCP头部和TCP数据进行校验和计算,接收端用于对收到的数据包进行验证

5 TCP的三次握手和四次挥手

5.1 三次握手过程

  TCP连接的建立时,双方需要经过三次握手,具体过程如下:

  (1)第一次握手

      Client进入SYN_SENT状态

      发送一个[SYN帧]来主动打开传输通道,该帧的SYN标志位被设置为1

      同时会带上Client分配好的SN序列号,该SN是根据时间产生的一个随机值,通常情况下每间隔4ms会加1

      除此之外,[SYN帧]还会带一个MSS(最大报文段长度)可选项的值,表示客户端发送出去的最大数据块的长度。

  (2)第二次握手

      Server端在收到[SYN帧]之后,会进入SYN_RCVD状态

      同时返回[SYN&ACK帧]给Client,主要目的在于通知Client,Server端已经收到SYN消息,现在需要进行确认。

      Server端发出的[SYN&ACK帧]的ACK标志位被设置为1

      其确认序号Ack(Acknowledgment Number)值被设置为Client的SN+1;

      Server端也随机生成一个SN序号;

      也可以携带一个MSS,[SYN&ACK帧]的MSS(最大报文段长度)表示的是Server端的最大数据块长度。

  (3)Client在收到Server的第二次握手[SYN&ACK确认帧}之后

      首先将自己的状态会从SYN_SENT变成ESTABLISHED,表示自己方向的连接通道已经建立成功,Client可以发送数据给Server端了。

      然后,Client发ACK帧给Server端,该ACK帧的ACK 标志位被设置为1

      其确认序号AN(Acknowledgment Number)值被设置为Server端的SN序列号+1。

      还有一种情况,Client可能会将ACK帧和第一帧要发送的数据,合并到一起发送给Server端。。

  (4)Server端在收到Client的ACK帧之后

      从SYN_RCVD状态会进入ESTABLISHED状态

      至此,Server方向的通道连接建立成功,Server可以发送数据给Client,TCP的全双工连接建立完成。

5.2 四次挥手具体过程

(1)第一次挥手

    主动断开方(可以是客户端,也可以是服务器端),向对方发送一个FIN结束请求报文,此报文的FIN位被设置为1

         正确设置Sequence Number(序列号)和Acknowledgment Number(确认号)。

    发送完成后,主动断开方进入FIN_WAIT_1状态,这表示主动断开方没有业务数据要发送给对方,准备关闭SOCKET连接了。

(2)第二次挥手

    正常情况下,在收到了主动断开方发送的FIN断开请求报文后,被动断开方会发送一个ACK响应报文

    报文的Acknowledgment Number(确认号)值为断开请求报文的Sequence Number(序列号)加1,该ACK确认报文的含义是:“我同意你的连接断开请求”。
    之后,被动断开方就进入了CLOSE-WAIT(关闭等待)状态,TCP协议服务会通知高层的应用进程,对方向本地方向的连接已经关闭,对方已经没有数据要发送了,若本地还要发送数据给对方,对方依然会接受。被动断开方的CLOSE-WAIT(关闭等待)还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。

    主动断开方在收到了ACK报文后,由FIN_WAIT_1转换成FIN_WAIT_2状态。

(3)第三次挥手

    在发送完成ACK报文后,被动断开方还可以继续完成业务数据的发送,待剩余数据发送完成后,或者CLOSE-WAIT(关闭等待)截止后,被动断开方会向主动断开方发送一个FIN+ACK结束响应报文,表示被动断开方的数据都发送完了,然后,被动断开方进入LAST_ACK状态。

(4)第四次挥手

    主动断开方收在到FIN+ACK断开响应报文后,还需要进行最后的确认,向被动断开方发送一个ACK确认报文

    然后,自己就进入TIME_WAIT状态,等待超时后最终关闭连接。

    处于TIME_WAIT状态的主动断开方,在等待完成2MSL的时间后,如果期间没有收到其他报文,则证明对方已正常关闭,主动断开方的连接最终关闭。

    被动断开方在收到主动断开方的最后的ACK报文以后,最终关闭了连接,自己啥也不管了。

6 握手挥手细节

6.1 处于TIME_WAIT状态的主动断开方,在等待完成2MSL的时间后,才真正关闭连接通道,其等待的时间为什么是2MSL

  2MSL翻译过来就是两倍的MSL。MSL全称为Maximum Segment Lifetime,指的是一个TCP报文片段在网络中最大的存活时间,具体来说,2MSL对应于一次消息的来回(一个发送和一个回复)所需的最大时间。如果直到2MSL,主动断开方都没有再一次收到对方的报文(如FIN报文),则可以推断ACK已经被对方成功接收,此时,主动断开方将最终结束自己的TCP连接。所以,TCP的TIME_WAIT状态也称为2MSL等待状态。

  有关MSL的具体的时间长度,在RFC1122协议中推荐为2分钟。在SICS(瑞典计算机科学院)开发的一个小型开源的TCP/IP协议栈——LwIP开源协议栈中MSL默认为1分钟。在源自Berkeley的TCP协议栈实现中MSL默认长度为30秒。总体来说,TIME_WAIT(2MSL)等待状态的时间长度,一般维持在1-4分钟之间。

  通过三次握手建立连接和四次挥手拆除连接,一次TCP的连接建立及拆除,至少进行7次通信,可见其成本是很高的。

6.2 为什么关闭连接的需要四次挥手,而建立连接却只要三次握手

  关闭连接时,被动断开方在收到对方的FIN结束请求报文时,很可能业务数据没有发送完成,并不能立即关闭连接,被动方只能先回复一个ACK响应报文,告诉主动断开方:“你发的FIN报文我收到了,只有等到我所有的业务报文都发送完了,我才能真正的结束,在结束之前,我会发你FIN+ACK报文的,你先等着”。所以,被动断开方的确认报文,需要拆开成为两步,故总体就需要四步挥手。

  而在建立连接场景中,Server端的应答可以稍微简单一些。当Server端收到Client端的SYN连接请求报文后,其中ACK报文表示对请求报文的应答,SYN报文用来表示服务端的连接也已经同步开启了,而ACK报文和SYN报文之间,不会有其他报文需要发送,故而可以合二为一,可以直接发送一个SYN+ACK报文。所以,在建立连接时,只需要三次握手即可。

6.3 为什么连接建立的时候是三次握手,可以改成两次握手

  三次握手完成两个重要的功能:一是双方都做好发送数据的准备工作,而且双方都知道对方已准备好;二是双方完成初始SN序列号的协商,双方的SN序列号在握手过程中被发送和确认。

  如果把三次握手改成两次握手,可能发生死锁。两次握手的话,缺失了Client的二次确认ACK帧,假想的TCP建立的连接时二次挥手,可以如下图所示:

  在假想的TCP建立的连接时二次握手过程中,Client发送Server发送一个SYN请求帧,Server收到后发送了确认应答SYN+ACK帧。按照两次握手的协定,Server认为连接已经成功地建立了,可以开始发送数据帧。这个过程中,如果确认应答SYN+ACK帧在传输中被丢失,Client没有收到,Client将不知道Server是否已准备好,也不知道Server的SN序列号,Client认为连接还未建立成功,将忽略Server发来的任何数据分组,会一直等待Server的SYN+ACK确认应答帧。而Server在发出的数据帧后,一直没有收到对应的ACK确认后就会产生超时,重复发送同样的数据帧。这样就形成了死锁。

6.4 为什么主动断开方在TIME-WAIT状态必须等待2MSL的时间

  原因之一:主动断开方等待2MSL的时间,是为了确保两端都能最终关闭。假设网络是不可靠的,被动断开方发送FIN+ACK报文后,其主动方的ACK响应报文有可能丢失,这时候的被动断开方处于LAST-ACK状态的,由于收不到ACK确认被动方一直不能正常的进入CLOSED状态。在这种场景下,被动断开方会超时重传FIN+ACK断开响应报文,如果主动断开方在2MSL时间内,收到这个重传的FIN+ACK报文,会重传一次ACK报文,后再一次重新启动2MSL计时等待,这样,就能确保被动断开方能收到ACK报文,从而能确保被动方顺利进入到CLOSED状态。只有这样,双方都能够确保关闭。反过来说,如果主动断开方在发送完ACK响应报文后,不是进入TIME_WAIT状态去等待2MSL时间,而是立即释放连接,则将无法收到被动方重传的FIN+ACK报文,所以不会再发送一次ACK确认报文,此时处于LAST-ACK状态的被动断开方,无法正常进入到CLOSED状态。

  原因之二:防止“旧连接的已失效的数据报文”出现在新连接中。主动断开方在发送完最后一个ACK报文后,再经过2MSL,才能最终关闭和释放端口,这就意味着,相同端口的新TCP新连接,需要在2MSL的时间之后,才能够正常的建立。2MSL这段时间内,旧连接所产生的所有数据报文,都已经从网络中消失了,从而,确保了下一个新的连接中不会出现这种旧连接请求报文。

6.5 如果已经建立了连接,但是Client端突然出现故障了怎么办

  TCP还设有一个保活计时器,Client端如果出现故障,Server端不能一直等下去,这样会浪费系统资源。每收到一次Client客户端的数据帧后,Server端都的保活计时器会复位。计时器的超时时间通常是设置为2小时,若2小时还没有收到Client端的任何数据帧,Server端就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,Server端就认为Client端出了故障,接着就关闭连接。如果觉得保活计时器的两个多小时的间隔太长,可以自行调整TCP连接的保活参数

7 TCP可靠数据传输

7.1 策略

  1)流水线机制

  2)累计确认机制

  3)单一重传机制

  4)触发重传的事件

    超时

    收到重复的应答

7.2 重传示例

    A:发送一个数据报,序号为92,数据大小为8b

  B:应答ACK100(92+8=100),但是丢失了

  A:发送一个数据报,序号为100,数据大小为20

  B:应答ACK120

  A:收到ACK120,更新sendbase为120,表示120及以前的全部正确传输完成

    

    A:发送一个数据报,序号为92,数据大小为8b

  A:发送一个数据报,序号为100,数据大小为20

  B:应答ACK100

  B:应答ACK120

  A:由于网络等原因,ACK100的应答超时了还没有到达,重发序号为92的数据

  A:收到ACK100,更新sendbase为100,表示100及以前的全部正确传输完成

  A:收到ACK120,更新sendbase为120,表示120及以前的全部正确传输完成

  B:再次收到序号为92的数据,重复了,舍弃,应答ACK120

  A:收到ACK120,更新sendbase为120,表示120及以前的全部正确传输完成

7.3 超时时时间间隔重置

  TCP的实现中,如果发生超时,超时时间间隔将重新设置,将超时时间加倍
 

7.4 快速重传机制

  如果sender收到对同一数据的3个ACK,则假定该数据之后的段已经丢失,发起重传
 

8 TCP的流量控制

  利用滑动窗口机制可以很方便地在TCP连接上实现发送方流量控制。通过接收方的确认报文中的窗口字段(标识接收方的能够处理的大小),发送方能够准确地控制发送字节数。
 

9 拥塞控制

9.1 简介

  前面的流量控制是避免发送方的数据填满接收方的缓存,但并不知道网络中发生了什么。

  一般来说,计算机网络都处在一个共享的环境。因此也有可能会因为其他主机之间的通信使得网络拥堵。在网络出现拥堵时,如果继续发送大量的数据包,可能会导致数据包时延、丢失,这时 TCP 就会重传数据,但是⼀重传就会导致⽹络的负担更重,于是会导致更⼤的延迟以及更多的丢包,这个情况就会进⼊恶性循环被不断地放⼤…
  于是,就有了拥塞控制,控制的⽬的就是避免「发送⽅」的数据填满整个⽹络。为了在「发送⽅」调节所要发送数据的数据量,定义了⼀个叫做「拥塞窗⼝」的概念。拥塞窗⼝ cwnd是发送⽅维护的⼀个的状态变量,它会根据⽹络的拥塞程度动态变化的。

  前⾯提到过发送窗⼝ swnd 和接收窗⼝ rwnd 是约等于的关系,那么由于加⼊了拥塞窗⼝的概念后,此时发送窗⼝的值是swnd = min(cwnd, rwnd),也就是拥塞窗⼝和接收窗⼝中的最⼩值。

9.2 拥塞控制四个算法

  慢启动(slow-start)、拥塞避免(congestion avoidance)、快重传(fast retransmit)、快恢复(fast recovery)。

9.2.1 慢启动
  TCP 在刚建⽴连接完成后,⾸先是有个慢启动的过程,这个慢启动的意思就是⼀点⼀点的提⾼发送数据包的数量。慢启动的算法规则:当发送⽅每收到⼀个 ACK,拥塞窗⼝ cwnd 的⼤⼩就会加 1。

    连接建⽴完成后,⼀开始初始化 cwnd = 1 ,表示可以传⼀个 MSS ⼤⼩的数据。
    当收到⼀个 ACK 确认应答后,cwnd 增加 1,于是⼀次能够发送 2 个
    于是又发送2个,当收到 2 个的 ACK 确认应答后, cwnd 增加 2,于是就可以⽐之前多发2 个,所以这⼀次能够发送 4 个
    于是又发送4个,当这 4 个的 ACK 确认到来的时候,每个确认 cwnd 增加 1, 4 个确认 cwnd 增加 4,于是就可以⽐之前多发 4个,所以这⼀次能够发送 8 个。

  可以看出慢启动算法,发包的个数是指数性的增⻓。有⼀个叫慢启动⻔限 ssthresh (slow start threshold)状态变量。

    当 cwnd < ssthresh 时,使⽤慢启动算法。
    当 cwnd >= ssthresh 时,就会使⽤「拥塞避免算法」。

  

9.2.2 拥塞避免
  前⾯说道,当拥塞窗⼝ cwnd 「超过」慢启动⻔限 ssthresh 就会进⼊拥塞避免算法。⼀般来说 ssthresh 的⼤⼩是 65535 字节。那么进⼊拥塞避免算法后,它的规则是:每当收到⼀个 ACK 时,cwnd 增加 1/cwnd。
  接上前⾯的慢启动的例子,现假定最初ssthresh 为 8

  当 8 个 ACK 应答确认到来时,每个确认增加 1/8,8 个 ACK 确认 cwnd ⼀共增加 1,于是这⼀次能够发送 9个 MSS ⼤⼩的数据,变成了线性增⻓。

  拥塞避免算法就是将原本慢启动算法的指数增⻓变成了线性增⻓,还是增⻓阶段,但是增⻓速度缓慢了⼀些。

9.2.3 重传
  当⽹络出现拥塞,也就是会发⽣数据包重传,重传机制主要有两种:超时重传、快速重传。

  当发生超时重传时:

    ssthresh 设为此时的cwnd /2

    cwnd 直接设为1

    重新进行慢启动
  当发生快速重传时:

    cwnd = cwnd/2 ,也就是设置为原来的⼀半;
    ssthresh = cwnd ;也就是设置为原来cwnd 的⼀半(和超时重传一样)

 
 

 

计算机网络12 TCP的更多相关文章

  1. 计算机网络及TCP/IP知识点(全面,慢慢看)

    TCP/IP网络知识点总结 一.总述 1.定义:计算机网络是一些互相连接的.自治的计算机的集合.因特网是网络的网络. 2.分类: 根据作用范围分类: 广域网 WAN (Wide Area Networ ...

  2. 计算机网络 之 TCP协议报文结构

    前言:上学期实训课,由于要做一个网络通信的应用,期间遇到各种问题,让我深感计算机网络知识的薄弱.于是上网查找大量的资料,期间偶然发现了roc大神的博客,很喜欢他简明易懂的博文风格.本文受roc的< ...

  3. 计算机网络要点---TCP

    计算机网络要点---TCP 浏览器在通过域名通过dns服务器找到你的服务器外网ip,将http请求发送到你的服务器,在tcp3次握手之后(http下面是tcp/ip),通过tcp协议开始传输数据,你的 ...

  4. Day 6-1计算机网络基础&TCP/IP

    按照功能不同,人们将互联网协议分为osi七层或tcp/ip五层或tcp/ip四层(我们只需要掌握tcp/ip五层协议即可) 每层运行常见物理设备: TCP/IP协议: Transmission Con ...

  5. 计算机网络(10)-----TCP的拥塞控制

    TCP的拥塞控制 拥塞(congestion) 在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏. 拥塞控制 拥塞控制就是防止过多的数据注入到网络中,这样可以使网 ...

  6. 计算机网络(7)-----TCP协议概述

    传输控制协议(Transmission Control Protocol) 概念 一种面向连接的.可靠的.基于字节流的传输层通信协议,由IETF的RFC 793定义.在简化的计算机网络OSI模型中,它 ...

  7. 12.TCP的成块数据流

    1.滑动窗口协议             TCP滑动窗口的可视化表示       我们将字节从1到11进行标号,接收方通告的窗口称为提供的窗口,它覆盖了第4字节到第9字节的数据,且通告窗口大小为6.发 ...

  8. 【计算机网络】TCP的流量控制和拥塞控制

    TCP的流量控制 1. 利用滑动窗口实现流量控制 如果发送方把数据发送得过快,接收方可能会来不及接收,这就会造成数据的丢失.所谓流量控制就是让发送方的发送速率不要太快,要让接收方来得及接收. 利用滑动 ...

  9. 计算机网络知识—(TCP)

    计算机网络在IT行业的重要性 IT即互联网技术,从事的工作和网络有很大的关系,前端要负责和后台(服务器)进行交互,其必然得经过网络,所以懂点网络知识有很大的帮助. 网络模型数据处理过程 传输层协议的作 ...

  10. 计算机网络:TCP协议建立连接的过程为什么是三次握手而不是两次?【对于网上的两种说法我的思考】

    网上关于这个问题吵得很凶,但是仔细看过之后我更偏向认为两种说的是一样的. 首先我们来看看 TCP 协议的三次握手过程 如上图所示: 解释一下里面的英文: 里面起到作用的一些标志位就是TCP报文首部里的 ...

随机推荐

  1. 某厂面试:如何优雅使用 SPI 机制

    代码不多,文章可能有点长.朋友面试某厂问到的 SPI 机制,联想到自己项目最近写到的 SPI 场景,文章简要描述下 SPI 机制的发展历程 产出背景 因为最近项目中使用分库分表以及数据加密使用到了 S ...

  2. 如何精简 Prometheus 的指标和存储占用

    前言 随着 Prometheus 监控的组件.数量.指标越来越多,Prometheus 对计算性能的要求会越来越高,存储占用也会越来越多. 在这种情况下,要优化 Prometheus 性能, 优化存储 ...

  3. 爬虫笔记之xpath

    目录 xpath如何取包含多个class属性 xpath获取当前标签下的所有文本(包括子标签) xpath如何取包含多个class属性 如果HTML结构是这样 <div class=" ...

  4. 【Shell脚本案例】案例3:批量创建100个用户并设置密码

    一.背景 新入职员工创建用户 二.常规操作 useradd zhangsan ls /home/ password zhangsan 三.考虑问题 1.实现自动输入密码,将其存到文件中 passwor ...

  5. 【算法题型总结】--6、BFS

    // 计算从起点 start 到终点 target 的最近距离 int BFS(Node start, Node target) { Queue<Node> q; // 核心数据结构 Se ...

  6. 【每日一题】【树的dfs递归,返回多次,注意都遍历完后才最终返回】2022年1月6日-112. 路径总和

    给你二叉树的根节点 root 和一个表示目标和的整数 targetSum .判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum .如果存在,返回 tr ...

  7. node版本管理工具fnm踩坑

    我建议是直接不要用fnm,还是老老实实用nvm吧 fnm下下来电脑防火墙会报毒(用github上推荐的cargo install fnm方式下载,并非第三方安装) Trojan.Generic.HgE ...

  8. Nmap常用方法

    1.扫描单个目标地址  在Nmap后面直接添加目标地址即可扫描  nmap 目标地址  2.扫描多个目标地址  如果目标不在同一网段,或在同一网段但不连续且数量不多,可以使用该方法进行扫描  nmap ...

  9. 一款极简的流媒体Web服务器(Streaming Media Web Server),提供视频音乐的在线播放功能

    一款极简的流媒体Web服务器(Streaming Media Web Server),提供视频音乐的在线播放功能 A extremely simple web server of streaming ...

  10. [whk] 解三元一次方程

    注:本篇运用大量 Katex ,如果炸了可能是运存不够也可能还要加载一会,重进几次即可.(都2202了,居然还存在我这种会炸公式的笔记本) 前言 写这篇随笔的由来是今天学习了: 不共线三点确定二次函数 ...