TCP 拍了拍你!!
发布日期:2021-06-27 12:55:17 浏览次数:28 分类:技术文章

本文共 9681 字,大约阅读时间需要 32 分钟。

TCP 拍了拍你!!

一、前言

TCP协议作为传输层协议中的重要点,不仅是一名软件工程师专业素养的体现,也是面试官口中的“必考点”。在此,我通过以下几点对TCP做一些梳理,希望对各位有用。

在这里插入图片描述
在开始梳理TCP知识点之前,我们先来了解一下TCP协议在互联网协议簇中的位置。如下图:
在这里插入图片描述
从最底层的协议说起,以太网(Ethernet)协议规定了电子信号如何组成数据包(packet),解决了子网内部的点对点通信。最具代表性的便是局域网中的五种常见的网络拓扑结构,如下图:
在这里插入图片描述
以太网解决了局域网内点对点之间的通信,那么多个局域网之间又该如何互通呢?也就是如何跨局域网通信?这时就需要使用 IP协议
IP 协议定义了一套自己的地址规则,称为 IP 地址。它实现了路由功能,允许某个局域网的 A 主机,向另一个局域网的 B 主机发送消息。如下图:
在这里插入图片描述
可IP 协议只是一个地址协议,并不保证数据包的完整。如果路由器丢包(比如缓存满了,新进来的数据包就会丢失),就需要发现丢了哪一个包,以及如何重新发送这个包。而这就需要依靠 TCP 协议。简单来说,TCP 协议的作用就是:保证数据通信的完整性和可靠性,防止丢包。传输层中有一个与TCP协议相似的协议——“UDP协议”,这里只做简单介绍,以此比较两种传输协议的区别,方便大家记忆。

二、TCP与UDP的区别

2.1、TCP与UDP

UDP(User Datagram Protocol)用户数据报协议:是无连接的,尽最大可能交付,没有拥塞控制,面向报文(对于应用程序传下来的报文不合并也不拆分,只是添加 UDP 首部),支持一对一、一对多、多对一和多对多的交互通信

TCP(Transmission Control Protocol)传输控制协议:是面向连接的,提供可靠交付,有流量控制,拥塞控制,提供全双工通信,面向字节流(把应用层传下来的报文看成字节流,把字节流组织成大小不等的数据块),每一条 TCP 连接只能是点对点的(一对一)。

2.2、区别

相信从两者的特点介绍中,你已看出了其中的一些区别,简单一句话就是:TCP协议是一个面向连接的、面向字节流的、可靠的传输层协议,而UDP协议是一个面向无连接的,尽最大可能交付的传输层协议。其实总结无非就是这三点区别。

在这里插入图片描述
说明:

  • 面向连接:所谓连接,就是客户端与服务器端的连接。TCP协议规定,两者在互相通信之前,需要经过三次握手(见下文)建立连接,而UDP协议没有相应建立连接的过程。
  • 可靠性:TCP协议为了保证连接的可靠性,加入了状态与可控制。(状态:TCP 会精准记录哪些数据发送了,哪些数据被对方接收了,哪些没有被接收到,而且保证数据包按序到达,不允许半点差错。
  • 可控制:当意识到丢包了或者网络环境不佳,TCP 会根据具体情况调整自己的行为,控制自己的发送速度或者重发)而UDP是没有状态,不控制传输的。
  • 基于字节流:因为UDP仅仅继承了IP的特性,UDP 的数据传输是基于数据报的,而 TCP 为了维护状态,将一个个 IP 包变成了字节流。

三、TCP报文首部字段

TCP报文是TCP层传输的数据单元,也叫报文段。那么TCP报文首部格式必然是TCP协议中不可或缺的要点,如下图:

在这里插入图片描述
说明:

  • 源端口、目的端口: (源IP,目的IP,源端口,目的端口)四元组唯一标识了一个TCP连接,所以TCP报文中的源端口和目的端口用于与IP首部中的IP地址来标识一个TCP连接
  • 序号:指报文段中的第一个字节序列号,用于对字节流进行编号。作用如下:
    (1)在SYN报文中交换彼此的初始化序列号
    (2)保证数据包按正确的顺序组装。
  • ISN:Initial Sequence Number(初始序列号)
  • 确定号:占 4 个字节,表示期望收到对方下一个报文段的第一个数据字节的序号,用来解决不丢包的问题。
  • 数据偏移:指TCP报文段的数据距离起始处的距离,实际指TCP报文段的首部长度。
  • 保留:保留为今后使用,目前置为0。
  • 窗口:定义对方必须维持的窗口大小,用来告知发送端接受端的缓存大小,以此控制发送端发送数据的速率,从而达到流量控制。窗口大小是一个16bit字段,因而窗口大小最大为65535。
  • 标记位:数据包的属性,用于控制TCP的状态机。
    (1)ACK(Acknowledge):确认序号标志,为1时表示确认号有效,为0表示报文中不含确认信息,忽略确认号字段。
    (2)PSH(Push function):当PSH为1时,表示是带有push标志的数据,指示接收方在接收到该报文段以后,应尽快将这个报文段交给应用程序,而不是在缓冲区排队。
    (3)RST(Reset):重置连接标志,用于重置由于主机崩溃或其他原因而出现错误的连接。或者用于拒绝非法的报文段和拒绝连接请求。
    (4)SYN:同步序号,用于建立连接过程,在连接请求中,SYN=1和ACK=0表示该数据段没有使用捎带的确认域,而连接应答捎带一个确认,即SYN=1和ACK=1。
    (5)FIN(Finish):终止连接标志,用于释放连接,为1时表示发送方已经没有数据发送了,即关闭本方数据流。
    (6)UGR:紧急指示符字段的值有效。当为1时表示紧急指针有效,为0则忽略紧急指针。
  • 校验和:奇偶校验,此校验和是对整个的 TCP 报文段,包括 TCP 头部和 TCP 数据,以 16 位字进行计算所得。由发送端计算和存储,并由接收端进行验证。
  • 紧急指针:当 URG 标志置 1 时,紧急指针才有效。紧急指针是一个正的偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号。TCP 的紧急方式是发送端向另一端发送紧急数据的一种方式。
  • 选项:TCP头部中的可选信息。最常见的可选字段是最长报文大小,它表示本端所能接受的最大报文段的长度,且每个连接方通常都在通信的第一个报文段(为建立连接而设置SYN标志为1的那个段)中指明这个选项。选项长度也不一定是32位的整数倍,所以要加填充位,即在这个字段中加入额外的零,以保证TCP头是32的整数倍。

四、TCP状态转换

在这里插入图片描述

五、TCP三次握手

在这里插入图片描述

5.1、三次握手过程及状态变化

在这里插入图片描述

说明:

  1. 首先,客户端与服务器端都处于CLOSED状态。
  2. 服务端的程序告诉它的TCP,它已经准备好接受一个连接,因此服务端开始主动监听某个端口,处于LISTEN状态
  3. 客户程序发出请求客户端主动打开,告诉它的TCP,它需要连接到特定的服务器。

第一次握手:

客户端随机初始化序列号 x,并将其TCP首部的序号字段置为该序号**(SEQ=x),同时将报文中的SYN标志置为1,表示该报文为SYN报文。用于向服务器端发起连接,且该报文不包含应用层数据。把该报文发送给服务端,未收到服务端回复之前,客户端都将处于SYN-SENT** 状态

第二次握手:

服务端收到客户端的连接请求报文后,首先自己也随机初始化一个的序列号y,并且回复报文的TCP首部序号字段置为该序号**(SEQ=y)**,同时将TCP首部确定号置为请求报文中的序号加1(ack=x+1,接着把SYN和ACK标志位都置为1,不携带应用层数据。之后,回复该报文给客户端,服务端未收到客户端回复之前都处于 SYN-RCVD 状态

第三次握手:

客户端收到服务端回复报文后,将序列号置为初始序列号加1(SEQ=x+1),同时将确定号置为回复报文中序列号加1(ack=y+1),接着将TCP首部ACK标志位置为1,最后将报文发送给服务端,客户端进入ESTABLISHED状态。(该报文可携带客户到服务器的数据)

当服务端收到客户端的应答报文后,也进入ESTABLISHED状态,则TCP连接建立成功,客户端和服务器就能互相发送数据了。

5.2、考点

5.2.1、为什么TCP连接不是两次或四次握手?

1、为什么不是两次握手?

引用《计算机网络》中所述的原因:防止已经失效的连接请求又被传送到服务器端,因而产生错误。但是这样解释也不太准确,其实从TCP产生上来说更加说服力。TCP协议的作用:保证数据通信的完整性和可靠性,防止丢包。
故此,为什么不是两次握手,是为了实现可靠数据传输。由于TCP 协议的通信双方,都必须维护一个序列号,用以标识发送出去的数据包中,哪些是已经被对方收到的。因此,三次握手的过程即是通信双方相互告知序列号起始值,并确认对方已经收到了序列号起始值的必经步骤。如果只是两次握手, 至多只有连接发起方的起始序列号能被确认,另一方选择的序列号则得不到确认。

2、为什么不是四次?

至于为什么不是四次,三次已经能解决了,为什么还要四次呢?

5.2.2、握手过程可以携带数据吗?

可以啊,不过只能在第三次握手过程可以携带数据。

如果前两次可以携带数据,那么当有人想攻击服务器端时,不断请求连接,进行SYN泛洪攻击,服务器必将消耗更多的时间和内存空间去处理这里数据,因此增加了服务器被攻击的风险。那为什么第三次可以呢?进行第三次握手时,客户端已经处于 ESTABLISHED 状态,也就是说服务端的接收、发送功能是正常的,这个时候相对安全了,因此可以传输数据。

5.2.3、多个客户端同时发起连接会怎么样?

如果服务端没有做策略处理的电话,来一个请求就响应一个,其他就等待。

六、TCP四次挥手

在这里插入图片描述

6.1、四次挥手过程及状态变化

在这里插入图片描述

第一次挥手:
当客户端打算关闭TCP连接时,客户端会发送一个将TCP首部 FIN 标识位置为1的报文,称为 FIN 报文,告诉服务器端客户端想要关闭TCP连接。客户端进入FIN_WAIT_1状态
第二次挥手:
当服务端收到客户端发来的 FIN报文 之后,向客户端发送一个 ACK应答报文,回应客户端已经收到了客户端想关闭TCP连接的请求消息,之后进入 CLOSED_WAIT 状态。
第三次挥手:
当客户端收到服务器端发送的 ACK应答报文 之后,知道服务器端已经知道自己要关闭TCP连接,继续等待服务器端发送关闭请求过来,进入 FIN_WAIT_2 状态。
服务器端处理完数据之后,再向客户端发送一个 FIN报文 ,告诉客户端服务器端数据已经处理完,可以关闭TCP连接,之后进入 LAST_ACK 状态。
第四次挥手:
当客户端收到服务器端发送的 FIN报文 之后,知道服务器端关闭TCP连接,因此回复一个 ACK应答报文 ,表示客户端已经收到服务器端关闭TCP的请求。然后客户端进入 TIME_WAIT 状态,等待两2MSL(最大分段生存期)时间,自动进入 CLOSE 状态,至此完成客户端TCP连接的关闭。
当服务器端收到客户端的 ACK应答报文 后,知道客户端已经知道自己要关闭TCP连接了,因此进入 CLOSE 状态,完成服务端的连接关闭。

6.2、考点

6.2.1、为什么要等待2MSL

本质原因是网络是不可靠的,所以TIME_WAIT状态就是为了用来重发可能丢失的ACK报文。如果发送方的最后一次ACK没有被接收方收到的话,那么接收方会进行重传第三次的释放连接请求,TIME_WAIT就是为了在这种情况下重发丢失了的ACK报文。因此,【接收方等待最后一次ACK+重发的第三次释放连接请求到达发送方的时间<=2MSL】所以要等2MSL(最大分段生存期)。

6.2.2、为什么不是三次挥手?

由于服务端在接收到客户端FIN报文后,一般不会立即给客户端返回FIN报文,告诉客户端关闭TCP连接。必须等到服务端所有的报文都发送完毕之后,才再发FIN报文。因此需要先回复一个ACK报文给客户端,表示已经知道客户端要关闭TCP连接,避免客户端一直重发FIN报文,造成网络混乱。

如果是三次挥手,那么相当于服务器端ACK报文和FIN报文一起发送了,那么就会导致客户端一直收不到ACK回应,客户端不断的重发FIN报文。

6.2.3、多个客户端同时发起挥手请求会怎么样?

如果服务端没有做策略处理的电话,来一个请求就响应一个,其他就等待。

七、TCP阻塞控制

在这里插入图片描述

TCP处理拥塞一般策略是基于三个阶段:慢启动、拥塞避免和拥塞控制。
在这里插入图片描述
说明:

  • 拥塞窗口(cwnd):目前发送端还能传输的数据量大小
  • 慢启动阀值(ssthresh):拥塞控制中慢启动阶段和拥塞避免阶段的分界点。初始值通常设为65535byte。
  • 发送窗口=min(rwnd,cwnd) (rwnd:接收窗口大小)

7.1、慢启动

由于初次传输数据时,不知道网络的情况,不知是稳定还是拥塞。如果过于快速进行传输数据,那么很容易造成大量丢包,导致网络更加拥塞,可能还会造成雪崩式的网络灾难。因此,拥塞控制采用慢启动来慢慢适应网络。

运行过程:

  • 建立TCP连接,设置cwnd为MSS(由连接建立期间最长段长度选项决定)
  • 每次接收到一个确认ACK时,窗口大小(cwnd)增加一个MSS值。
  • 当初始MSS为1时,第一轮传输后,cwnd=2;第二轮传输后,cwnd=4,第n轮传输后,cwnd=2^n(二的n次方);但是由于网络延迟,有ACK会被延迟,所以窗口大小的增长是小于2的幂次。

由于网络可承受传输数据量大小有限,需要设置一个阀值来限制传输数据量,慢启动阶段称为慢启动阀值(ssthresh),初始值通常设为65535byte。那么当cwnd到达这个阀值之后,该如何去避免拥塞呢?这就需要进入了拥塞避免阶段。

7.2、拥塞避免

由于慢启动阶段数据传输接近于2的幂次,cwnd过于大,所以为了避免过多的数据超过网络可承受阀值,最后导致过多的数据包重发,造成网络拥塞。所以拥塞避免阶段,采用每一轮数据传输后,cwnd只增加1,就算超过了网络可承受阀值,也不需要过多数据包需要重传。

7.3、快速重传和快速恢复

说明:

  • RTO:重传超时
  • RTT:往返时间,取决于一个段到达目的端并接收到一个确认所需要的时间。
    快速重传:
    快速重传解决的是是否需要重传问题,不是快速传输问题。
    TCP传输过程中,由于某一段丢失了,导致接收端收到了许多失序的段,受限于有限的存储器大小,这些段不可能都被存储下来。因此,为了缓解这种情况,遵循三次重复ACK原则。丢弃失序段序号之后的段,立即重发缺少的段。比如,传输中丢失了第21个包,即使22、23、24到达了接收端,接收端也只返回第20个包的ACK。当发送端收到三个ACK后,立即重发第20包后的数据包,不用等待。快速在于不用等待一个RTO时间

选择重传

由于存储器大小限制不那么大了,所以数据可以失序到达,并被接收的TCP暂时存储,并标记它们为失序的段,直到缺少的段到达。但是TCP确保了传递给进程的段是无失序的。而选择性的传输失序的段的重传就称为选择重传。如快速重传的例子,无需再重传第20包后的数据包,只需传输第21数据包即可。

快速恢复:

当发送端收到三次重复ACK后,发现丢包,并且当前网络出现拥塞了,那么发送端就会进入快速恢复阶段。这时发送端会将拥塞阀值和cwnd降低为当前cwnd的一半,且cwnd开始以线性进行增加。

八、TCP流量控制

在这里插入图片描述

对于发送端和接收端,TCP需要将发送的数据放到发送缓存区,将接收的数据放到接收缓冲区。而TCP流量控制就是通过获知接收缓存区的大小,控制发送端的发送。当接收端的缓存区满了,就通知发送端不再继续发送数据包。

8.1、TCP滑动窗口概念

在这里插入图片描述

发送窗口:

在这里插入图片描述
因此,发送窗口结构可分为:已发送并被确认、已发送未被确认、未发送但可发送、未发送且不可发送四个部分。

接收窗口:

在这里插入图片描述
接收窗口就更简单了,只需要一个REV.NXT来表示下一个接收的位置和REV,WND表示窗口大小即可。

8.2、流量控制过程

在这里插入图片描述

这里我们借助这个例子来说明一下流量控制原理,就算是再复杂的情况,原理也是一样的。
首先,假设建立TCP连接之后,发送窗口和接收窗口初始化为4K。现在发送端向接收端发送2k数据包。发送窗口中可用窗口为2k,当数据到达后接收窗口变为2k,这好理解。接着接收端向发送端回复一个ACK并携带当前接收窗口大小2k。当发送端收到ACK报文后,知道接收窗口大小为2k。因此,继续发送2k数据,那么发送窗口的可用窗口就为0,则需要移动,获取新的数据。而接收窗口,由于数据处理慢或者负载原因导致两次接收的数据都还在接收缓存区,未被处理。所以当前接收窗口大小为0,回复ACK和接收窗口大小为0,那么发送端就需要进入阻塞等待,发送窗口变为0,继续等待下一个ACK告知发送端接收窗口大小,从而调整当前发送数据量。等待一段时间后,收到一个ACK,知道了接收窗口大小为2k,所以调整发送窗口为2k,发送端继续发送数据,这次传输1k。最后,接收端收到数据后,接收窗口变为1k。
虽然这个发送窗口大小受当前接收窗口和阀值大小影响,但是只要知道:
发送窗口大小=min(rwnd,cwnd) 即可。
【注解】
rwnd:接收窗口大小
cwnd:慢启动阀值

九、TCP超时重传算法

在这里插入图片描述

对于TCP超时重传机制,我们知道Timeout的设置是十分重要的。如果Timeout设置太长,重发就会很慢,效率性能低下;如果Timeout设置太短,就会导致数据包可能还没有到达目的端,发送端就重发了,从而增加网络拥塞,导致更多的超时,最后使得网络雪崩式瘫痪。同时不同的网络情况,Timeout也不一样,因此需要动态设置Timeout。
TCP引入了RTT(往返时间),从而方便的设置RTO(重传超时时间),使得重传机制更加高效。

9.1、经典方法

计算过程:

  • 首先,先采样RTT,记下最近好几次的RTT值
  • 对多次采样RTT做平滑计算SRTT
    公式:SRTT = ( α * SRTT ) + ((1- α) * RTT)(其中的 α 取值在0.8 到 0.9之间,称为加权移动平均)
  • 计算RTO
    公式:RTO = min[ UBOUND,max[ LBOUND,( β*SRTT ) ] ]
    UBOUND是最大的timeout时间,上限值
    LBOUND是最小的timeout时间,下限值
    β 值一般在1.3到2.0之间。

9.2、Jacobson/Karels算法

由于经典算法中采用到了加权移动平均参数,如果采样RTT波动很大的话,在做平滑计算SRTT之后,很难发现。因此,该算法引入了新的RTT采样和平滑过的SRTT的差来做因子来计算。

  • 计算平滑RTT:SRTT = SRTT + α (RTT – SRTT)
  • 计算加权移动平均:DevRTT = (1-β)DevRTT + β(|RTT-SRTT|)
  • 计算RTO: RTO= µ * SRTT + ∂ *DevRTT
    备注:Linux下,α=0.125,β=0.25,µ=1,∂=4

十、TCP快速打开(TFO)原理

在这里插入图片描述

由于建立TCP连接需要三次握手,因此每次建立都需要,那么必然有些麻烦。所以TCP引入了TCP快速打开原理(TFO)来优化TCP握手流程。

10.1、首轮三次握手

首先,客户端先向服务端发送SYN报文,当服务端收到SYN报文后,通过计算得到一个SYN Cookie,并将它发到TCP报文的Fast Open选项中,返回回应报文给客户端。当客户端拿到这个Cookie之后,将其缓存下来,其他流程不变,完成首次三次握手。

10.2、之后的三次握手

由于首次三次握手,客户端已经将Cookie缓存下来了。所以之后客户端会将Cookie、HTTP请求、SYN发给服务端。服务端去验证Cookie的合法性,如果不合法就直接扔掉,如果合法就返回ACK+SYN,之后客户端收到后就返回ACK报文。

可能你会问,这还是三次握手啊,没有变化啊!其实在验证了Cookie的合法性之后,就可以返回服务端的HTTP响应了,如果之前就需要等待第三次握手ACK到达之后,客户端才可以进行HTTP请求。如下图:

在这里插入图片描述

10.3、TFO的优势

相对于首次三次握手,TFO并无优势可言。但是在之后的三次三次握手过程中,只要服务端验证了Cookie的合法性就可以直接返回HTTP响应,而这直接提前了一个RTT时间进行数据传输,相对于大量的非首轮三次握手,将大大提高TCP的响应速度。

十一、TCP时间戳的作用

在这里插入图片描述

TCP时间戳是TCP报文首部的一个可选项,占10个字节。
它解决了TCP中的两大问题:

  • 计算往返时延RTT(Round-Trip Time)
  • 防止序列号的回绕问题

11.1、计算往返时延RTT

在TCP超时重传的经典算法中,需要对RTT进行采样。因此,需要获取一个精确的RTT,才能获得一个更符合网络情况的RTO。但是在没有时间戳的情况下,计算RTT必然会遇到这两种情况:(如下图)

  • 情况(a):如果ACK没回来,进行重传。那么你计算第一次发送和ACK的时间,明显RTT算大了。
  • 情况(b):如果ACK回来慢了,导致发送端重传,但刚重传不一会儿,之前ACK就到达发送端。那么你算重传的时间和ACK回来的时间的差,就会将RTT算短了。
    在这里插入图片描述
    因此,引入时间戳很好的标识了重传和ACK的时间差。如现在客户A向服务B发送一个报文P1,并设置TCP报文首部时间戳为客户A发送时的内核时刻T1,。当服务B收到报文P1后,将TCP报文首部Timestamp echo字段为P1报文中的时间戳T1,此时服务B主机时刻为T。之后服务B向客户A回复一个含有ACK的报文P2。客户A收到P2后,解析出报文P2中的Timestamp echo选项,从而得到T1,也就是客户A最初发送的时刻。此时客户A主机的时刻为T2,因此就可得到RTT=T2-T1。

11.2、防止序列号回绕的问题

直接上例子!(序列号范围:0~2^32-1)

假设TCP序列号范围为0~2,当到达2时就回到0。
在这里插入图片描述
当第四次传输数据时,第二次传输的数据包到达了服务端,而此次传输的数据包也到了,同时出现两个序列号为1的数据包,服务端如何区分?这就是序列号回绕问题。
因此,采用时间戳Timestamp很好的将每次发包时间记录在TCP时间戳timestamp选项中,即使是两者的发包序列号相同,也能根据时间戳来进行分辨。

十二、SYN Flood攻击原理

在这里插入图片描述

TCP三次握手前,服务端的状态会从CLOSED变为LISTEN, 同时在内部创建了两个队列:半连接队列和全连接队列,即SYN队列和ACCEPT队列。

12.1、半连接队列

当客户端发送SYN报文到服务端,服务端收到以后回复ACK和SYN,状态由LISTEN变为SYN_RCVD,此时这个连接就会被推入SYN队列,也就是半连接队列。

12.2、全连接队列

当客户端返回ACK, 服务端接收之后,完成TCP三次握手。这个时候连接等待被具体的应用取走,在被取走之前,它会被推入另外一个 TCP 维护的队列,也就是全连接队列(Accept Queue)。

12.3、SYN Flood攻击

SYN Flood攻击就是用客户端在短时间内伪造大量不存在的IP地址,并向服务疯狂发送SYN请求连接报文。因此,使得服务端产生两种危险后果

  • 处理大量的处理大量的SYN请求包并返回对应ACK, 势必有大量连接处于SYN_RCVD状态,从而占满整个半连接队列,无法处理正常的请求。
  • 由于是不存在的 IP,服务端长时间收不到客户端的ACK,会导致服务端不断重发数据,直到耗尽服务端的资源。

12.4、如何应对SYN Flood攻击

解决方案:

  • 增加半连接队列的容量。
  • 控制 SYN + ACK 重试次数,避免大量的超时重发。
  • 利用 SYN Cookie 技术,在服务端接收到SYN后不立即分配连接资源,而是根据这个SYN计算出一个Cookie,连同第二次握手回复给客户端,在客户端回复ACK的时候带上这个Cookie值,服务端验证 Cookie 合法之后才分配连接资源。
    在这里插入图片描述

转载地址:https://blog.csdn.net/weixin_43452424/article/details/111499757 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:浅谈数字证书的今生前世
下一篇:Elasticsearch 分词器

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2024年03月27日 14时12分24秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

深度linux内核升级,深度操作系统 2020.11.11 更新发布:内核升级 2019-04-21
sql 拆解函数_SQL入门50题详解(含知识点讲解及代码运行步骤拆解) 2019-04-21
java和python交互 jni_Python基于pyjnius库实现访问java类 2019-04-21
macbook pro 卸载mysql_MacBook Pro全新重装OS X Yosemite 2019-04-21
已达到计算机的连接数最大值无法再同此远程计算机连接_电脑远程访问已达到计算机的连接数最大值怎么办?解决方法很简单... 2019-04-21
mysql表名长度_JavaWeb之MySQL(一) 2019-04-21
mysql服务器语法_Mysql语法 2019-04-21
pdf 模版 汉字和数字_《吉林大学珠海学院毕业论文(设计)模板》(汉字标题版) .pdf... 2019-04-21
python bottle部署_nginx+uwsgi+bottle python服务器部署 2019-04-21
python双击py一闪_Python脚本在双击.py时无法正常运行 2019-04-21
redis logfile为空_关于Redis(二) 2019-04-21
mysql 设计两个主键都不可重复_程序员面试备战篇:18个经典MySQL面试专题解析(干货分享答案)... 2019-04-21
下列关于python2.x和3.x的区别说法正确_Python 2.x和Python 3.x版本有哪些区别?【面试题详解】... 2019-04-21
git更换_git命令 2019-04-21
hp-ux 查看系统负载_Linux性能调优 | 平均负载的理解和分析 2019-04-21
elementui的tree组件页面显示不出数据_vue路由及组件 2019-04-21
android hook sensor数据_最近,又有人在谈论Android的前景了!深入解析趋势及必备技术点... 2019-04-21
python 动态tabel的数据爬取_使用requests爬取python岗位招聘数据 2019-04-21
input js number 整数_JS基础简单小结(1) 2019-04-21
二阶差分预测后数据还原公式_xgboost系列丨xgboost原理及公式推导 2019-04-21