jjzjj

RTCP协议详解(SR、RR、SDES、BYE、APP、NACK、TCC、PLI、SLI、FIR )

恋上豆沙包 2023-05-27 原文
RTCP 协议规范中定义了五种类型的 RTCP 包:接收⽅报告( RR )、发送⽅报告( SR )、源
描述( SDES )、成员管理( BYE )和应⽤程序定义( APP )。
SR: payload type=200
RR:payload type=201
SDES: payload type=202
BYE:payload type=203
APP:payload type=204
RTPFB:payload type=205

PSFB:payload type=206

RTCP_RTP_FB_NACK_FMT(1): NACK重传, type-205

RTCP_RTP_FB_RTX_FMT(1):RTX重传,type-205

RTCP_RTP_FB_CC_FMT(15):Transport-cc 带宽估计,type-205

RTCP_PLI_FMT(1): picture重传, type-206

RTCP_SLI_FMT(2): Slice重传, type-206

RTCP_FIR_FMT(4): 关键帧重传, type-206

RTCP_REMB_FMT(15): 带宽估计, type-206

版本号(V):对于当前版本的RTP协议,版本号为2(截止到本书编纂为止),目前还 没有推出新版本的计划,并且之前的版本并没有广泛的被使用.

填充(P):填充位表示,所要填充的数据已经超出了目前所能容纳的位数。如果此位 被设置为1,那么意味着包尾已经被一个或多个八位字节填充,最后一位八位所填充的 内容表示此包的总数大小。

条目计数(IC):某些包类型中包含了一个list的条目,可能作为固定的、用于特定类   型的信息的补充。这些条目字段需要标示出包中包含的条目的总数(这个字段在不同的 包中有不同的命名方法,这取决于具体如何使用此字段)。每个RTCP包最多包含31个   条目,同时也受到MTU(maximum transmission unit)的限制。如果需要传输超过31 个条目的场景,那么应用程序必须生成多个RTCP包。Item  Count字段为0的时候表示此包中的条目为空(但是并不意味着包中内容为空)。如果不需要Item count字段那么此字段可以用于其他的目的。

包类型(PT):此字段标识了传输的包中所携带的信息的类型。在RTP的规范中定义了 五种标准数据包类型,将来可能还会定义其他的类型(例如,报告额外统计信息或者传 递其他特定源的信息)。

长度:此字段标识包头之后的内容总长度。因为所有的RTCP的数据包的长度必须为32 位的整数倍,所以这个字段放的是32位字的个数,因为如果按照八位字节计算会出现   此字段和总长度不一致的情况。0是一个有效长度,表示这个包只包含4个8位字节的包 头(包头字段IC在这种情况下也是0)。

RTCP包中复合包的结构

RTCPRR的格式:

 每一个报告块(report block)都是描述单个同步源的接收质量,而报告者(reporter)从当前报告的间隔期间,接收从该同步源发过来的RTP包。每一个RTCP的RR包总共有31个报告  块。如果有超过31个激活的发送者,那么接收者应该在一个复合数据包中发送多个RR数据包,每个报告块有7个字段,总共24个字节。

Reportee(被报告者)SSRC标识此报告块相关的参与者。报告块中的统计数据,表示的是在生成RR数据包的参与者处,被报告方接收到的同步源的数据包的接收质量。

丢包率(loss  fraction)的定义是在这个报告间隔中所丢失包的数量,除以预期到达的数量。丢包率表示为一个定点数,该定点数的二进制小数点位于字段的左边缘。即丢包率乘 以256后的整数部分(即如果传输中有1/4的包丢掉,那么丢包率应该是1/4 * 256 = 64). 如果接收到的包的数量大于预期(由于存在重复包的情况),使得丢包数为负值,那么丢 包的部分设置为0.

累计丢包数是一个24位带符号的整数,它表示预期应该到达的包的数量,减去实际接收到 的包的数量。预期的包数的定义是,最后接收到的扩展序列号,减去接收到的初始序列号。接收到的包的总数包括任何延迟到达或者重传过来的包,因此可能会大于预期的数量,因此累计丢包数有可能是负值。累计丢包数的计算区间是统计的整个会话期间的,而不是在每个间隔期间。如果在会话期间丢包的总数大于0x7FFFFF,那么此字段会在0x7FFFFF处于最大饱和值。

理论计算方式, packet lost = 期待得到报文数量 - 实际收到报文的数量。

实际计算方式, packet lost = 期待收到最新sequence - 第一次收到报文的sequence。

在同步源的RTP数据包中接收到的扩展最高序列号(extended highest sequence number) 的计算,由于可能存在包重新排序的情况,所以并不一定是接收到的最后一个RTP包的扩展序列号。扩张序列号是 基于会话计算的,而不是基于包间隔计算的。

extended_seq_num = seq_num + (65536 * wrap_around_count)

其中wrap_around_count为sequence翻转的次数

到达间隔抖动(Interarrival jitter)是对被报告者(Reportee)同步源发送的数据包的网络传输时间统计方差的估计。它是以时间戳单位衡量的,因此它像RTP时间戳一样用32位无 符号整数表示.

 J(i) = J(i-1) + (|D(i-1,i)| - J(i-1))/16

D(i,j) = (Rj - Ri) - (Sj - Si) = (Rj - Sj) - (Ri - Si)

ISiRiD(i, i-1)J(i)
101000
2203000
34049-10.0625
4607450.3711

最后一个发送者报告(last sender report,LSR)时间戳是64位NTP(网络时间协议(Network Time Protocol))格式的时间戳中间的32位,包含在最近从被报告者的SSRC接收到的RTCP的SR包中。如果SR没有收到,那么此字段可以设置为0.

自上次发送者报告起的延迟(delay since last sender report,DSLR)是从被报告者SSRC接收到最后一个SR数据包到发送此接收报告块之间的延时,以1/65,536秒为单位。如果没从 该被报告者收到SR,则DLSR字段设置为0.

发送方可以使用LSR和DLSR字段来计算它与每个接收方之间的往返时间(rtt)。当接收到  一个与之相关的RR包时,发送方用当前的时间减去LSR字段,以得到发送SR到接收此RR之  间的延迟。发送方然后再减去DLSR字段以消除接收方延迟带来的偏移,从而获得网络往返时间。

RTT=NTP-LSR-DLSR.

RTCPSR包的格式

发送者报告的包类型为200,有效负载包含一个24字节的发送者信息 块,后面跟着0个或多个接收方报告块,由RC字段标识,类似于接收方报告报。当发送者  也是接受方的时候,接收方报告块就出现了.

NTP时间戳是一个64位的无符号值,表示发送这个RTCP SR包的时间。它的格式是NTP时间戳,时间从1900年1月1日开始计算秒,低32位代表秒的小数部分(fractions of second)

(也就是64位定点值,二进制小数点位于32位之后)。如果要将UNIX的时间戳(从1970   年1月1日开始的秒数)转化为NTP时间,那么需要添加2,208,988,800秒。

RTP时间戳与NTP时间戳的对应的时间是相同的,但是,它是以RTP媒体时钟的基准单位表  示的。这个值,通常与前一个数据包的RTP时间戳不同,因为自该数据包中的数据被采样    已经经过了一段时间了。

发送方的包计数,是这个同步源自会话开始以来,生成的数据包的总数。发送方的字节计 数是这些数据包的有效负载(playload)中包含的字节数(不包括包头或者填充)。如果发送方改变其SSRC(例如,由于产生冲突),则会重置发送方的包计数以及字节计数  字段。

RTCP SDES:源描述(Source Description

RTCP也可以用来传递源描述(SDES)数据包,提供参与者认证和补充性细节,如位置、    电子邮件地址和电话号码。

应用程序有可能生成SDES项为空列表的包,在这种场景下,RTCP公共包头中的SC和length 字段都为0.在正常情况下,SC应该为1(混流器(mixers)和转换器(translators)所聚集 的转发信息产生的包会有较大的SDES项的列表)。

 

每个SDES项中的条目都是以连续的方式打包到包中,没有分隔或者填充。条目列表(list of item)以一个或者多个空的字节结束,当解析到第一个字节为0类型的时候,意味着这个列 表结束。0类型字节后面不会跟长度字节,但是如果需要填充,则包括其他的空字节,直到 达到32-bit边界为止。这个填充(padding)与RTCP包头中的P位表示的填充是分开的。带   有零项的列表(四个空字节)是有效的,但是没有意义。

CNAME项(type  =  1)为每个参与者提供了一个规范名称(CNAME)。它提供了一个独立于同步源的稳定且持久的标识符(因为如果应用程序重启或发生SSRC冲突,SSRC将改         变)。CNAME可以用于关联来自不同RTP会话的参与者的多个媒体流(例如,关联需要同   步的语音和视频),以及在媒体工具重启时命名参与者。这是唯一的强制性的SDES条目,  所有实现都需要发送SDES CNAME项。

RTCP 释放连接(bye) : 成员控制

RTCP通过RTCP的Bye包为成员提供松散的控制,如果收到Bye表明某些参与者已经离开了 会话。Bye包是在参与者离开会话的时候,或者当其他参与者因为冲突而改变SSRC的时候 生成的。Bye包有可能会在传输过程中丢失,并且有些应用程序也不能生成此包。所以,即便没有收到Bye包,针对一段时间没有活跃的参与者,接收方应该有超时机制。

RTCP BYE包不会终止参与者之间的任何其他关联关系。Bye包的标识类型为203,公共的RTCP包头中的RC字段表示SSRC标 识符的数量。其存在为0的可能性,标识为0时无用。在接收到Bye包时,实现时应该假设 此源已经离开了会话,并忽略来自该源的任何后续的RTP和RTCP包。最重要的是,当收到Bye包之后,需要为此参与者保留一段时间的连接状态,因为要允许延迟到达的数据包被接收到。

 Bye包还可能包含了表示离开会话原因的文本,适合在用户界面中显示。但是,这个文本是可以选填的,在实现过程中我们需要去接收它(即使文本可能会被忽略)。

RTCP APP:应用程序定义的RTCP

最后一类RTCP包(APP)允许应用程序来自己定义扩展。它的包类型为204,由4个字符组成唯一的标识,每个字符都得从ASCII字符集中选择,并区分大小写。建议选择包名称来匹配它所代表的应用程序,并由应用程序来协调子类型值的选 择。包其余部分被用于应用程序的特定需求。

应用程序自定义的包用于RTCP的非标准扩展和验证新特性。目的是,验证者首先使用APP 来验证新特性,然后如果新特性有广泛的用途,那么就注册为新的包类型。一些应用程序 生成的包或实现方案,应该忽略识别不出来的应用程序包。

组包Packing)问题

RTCP包不会单独发送,而是组包成一个复合数据包进行传输。生成复合RTCP包的参与者是活跃的数据发送方,那么该复合包必须以RTCP  SR包开始。否则必须从RTCP  RR包开始。即使还没有发送或接收数据,这也是正确的,在这种情况下,SR/RR包不会包含接收方的报告块(包头字段RC为0)。另一方面,如果从多个源接收数据,并且报告太多,导致无法放入一个SR/RR包,则复合后的数据应以一个SR/RR包开始,后面在跟着多个RR包。跟在SR/RR包后面的是一个SDES包。这个包必须包含一个CNAME条目。它可能包含其他的 条目。包含其他(非CNAME)SDES条目的频度由使用中的RTP配置文件决定。

Bye包必须做为最后一个数据包发送。要发送的其他RTCP包可以按 任何顺序。这些严格的排序规则,旨在使数据包的校验更容易,因为错误定向的数据包, 大概率不会满足这些约束。

在生成复合RTCP包时,一个潜在的问题就是如何处理大量活跃发送者的会话。如果存在超 过31个活跃的发送者,那么有必要在复合包中增加额外的RR包。这可以根据需要重复此过 程,直到达到MTU的上限。如果发送方太多,以致于接收方报告不能被MTU容纳,则必须 忽略某些发送方的接收报告。如果出现这种情况,那么被忽略的报告,应该在生成的下一 个复合包中被包含(要求接收方跟踪每个间隔中报告的源)。

有时候需要将一个复合RTCP包填充并超出其原始大小。在这种场景下,填充只是添加到复 合包中的最后一个RTCP包中,P位(P bit)在最后一个包中被设置。

重传NACK(RTPFB-FMT(1))

重传请求需要两个步骤:需要为重传请求定义数据包格式,并且必须修改时序规则以允许⽴立即反馈。

否定应答(NACK)的格式如图9.11所示。NACK包含⼀一个表示丢包的包标识符和⼀一个位图,该位图显示以下16个包中的哪⼀一个丢失了了,值为1表示丢失。

反馈包作为⼀一个复合RTCP包的⼀一部分发送,其⽅方式与所有其他RTCP包相同。它们放在复
合包的最后,在SR/RR和SDES项之后。

RTX重传

PT=205,FMT=1 和 NACK 一样

1、rtx 在sdp中的体现:

a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96

a=ssrc-group:FID ssrc rtxssrc

97 为rtx负载类型,90000为时钟频率,一般和要重传的包的时钟频率相同。

a=fmtp:97 apt=96 表示 负载类型为97的rtx包重传的是负载类型为96包。

a=ssrc-group:FID ssrc rtxssrc 将rtx包的ssrc与重传包的ssrc关联起来。

另外,97 rtx负载类型必须出现在sdp的对应m行里。 

Original Rtp Packet Payload为要重传包的负载数据,OSN为原始包的sequence number,Rtp Header除了Ssrc、负载类型和rtx的sequence number外,其余部分与原始包相同。

Rtx原理:重发的包封装到RTX包里发送,RTX包与原RTP有不同的SSRC,不同的rtpseq,但是timestamp与丢失包的时间戳相同。

Rtx优势:rtp重传包在带宽估计时不计入运算,使用rtx比较方便,不使用rtx统计丢包率有时会出现负值

Rtxpayload:前两个字节代表丢失包的rtp seq,因此rtx包比丢失的rtp包多2个字节

临时最大码率请求TMMBR(RTPFB-FMT(3))

webRTC中被废弃

临时最大码率通知TMMBR(RTPFB-FMT(4))

对TMMBR的相应

webRTC 中被废弃

PLI(PSFB-FMT(1))

FCI为空

PLI消息用于解码端通知编码端我要解码的图像的编码数据丢失了。对于基于帧间预测的视频编码类型,编码端收到PLI消息就要知道视频数据丢失了,由于帧间预测需要基于前后完整的视频帧才能解码(例如H264中,存在B帧,需要参考前后帧才能解码),前面的数据丢失了,后面的视频帧不能正常解码出图像,此时编码端可以直接生成一个关键帧,然后发送给解码端。

SLI(PSFB-FMT(2))

。。。 

FIR(PSFB-FMT(4))

 当解码端需要刷新时,可以发送FIR消息给编码端,编码端此时发送关键帧,刷新解码端。这有点类似PLI消息,但是PLI消息是用于丢包情况下的通知,而FIR却不是,在有些非丢包情况下,FIR就要用到。举两个例子:
1)解码端需要切换到另一路不同视频时,由于需要新的解码参数,所以可通过发送FIR消息,通知编码端生成关键帧,获取新的解码参数,刷新视频解码器;
2)在视频会议中,新用户随机时刻加入,各个编码端发送的视频不一定都是关键帧,所以新用户不一定能正常解码。此时该新加入用户发送FIR消息,通知各个编码端给它发关键帧,获取关键帧后即可正常解码。

REMB(PSFB-FMT(15)) 

它描述了一个绝对值时间戳选项,用于带宽估计。该反馈消息用于通知一个在同一RTP会话上有多个媒体流的发送方, 通知它在该RTP会话的接收方路径上的总的估计可用比特率。

在用于反馈消息的公共数据包头中(如[RFC4585]的6.1节所定义),“数据包发送者的SSRC” 字段指示通知的来源。 不使用“媒体源的SSRC”,并且应将其设置为0。在其他RFC中也使用零值.

媒体发送方对符合此规范的REMB消息的接收将导致该消息在RTP会话上发送的总比特率等于或低于此消息中的比特率。 新的比特率限制应尽快应用。 发送者可以根据自己的限制和估计自由应用其他带宽限制。

How 怎么实现 REMB?

  1. SDP 中包含如下属性
a=rtcp-fb:<payload type> goog-remb
a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time

 V=2 P=0 FMT=15 PT=206  SSRC of media source=0 

unique identifier ='R' 'E' 'M' 'B'

同步源的个数NUM SSRC:

带宽的指数BR EXP:

带宽的底数BR Mantissa:

所反馈的SSRC 一个或多个值 SSRC feedback (32 bits) Consists of one or more SSRC entries which this feedback message applies to.

receiver-bit-rate = mantissa * 2^exp

例子:

Transport-CC(RTPFB-FMT(15))

Transport-cc指的是Transport-wide Congestion Control。WebRTC最新的拥塞控制算法(Sendside BWE)基于Transport-cc,接收端记录数据包到达时间,构造相关RTCP包,然后反馈给发送端,在发送端做带宽估计,从而进行拥塞控制.WebRTC中为了使用Transport-cc,需要用到RTP报头扩展以及增加新的RTCP类型。这里我们介绍下Transport-cc中的RTP以及RTCP。

报文格式

Transport-cc中,收流客户端通过TransportFeedback RTCP向发送端反馈收到的各个RTP包的到达时间信息。首先我们看下TransportFeedback包格式定义

  • base sequence number:2字节,TransportFeedback包中记录的第一个RTP包的transport sequence number,在反馈的各个TransportFeedback RTCP包中,这个字段不一定是递增的,也有可能比之前的RTCP包小
  • packet status count:2字节,表示这个TransportFeedback包记录了多少个RTP包信息,这些RTP的transport sequence numberbase sequence number为基准,比如记录的第一个RTP包的transport sequence numberbase sequence number,那么记录的第二个RTP包transport sequence numberbase sequence number+1
  • reference time:3字节,表示参考时间,以64ms为单位,RTCP包记录的RTP包到达时间信息以这个reference time为基准进行计算
  • feedback packet count:1字节,用于计数发送的每个TransportFeedback包,相当于RTCP包的序列号。可用于检测TransportFeedback包的丢包情况
  • packet chunk:2字节,记录RTP包的到达状态,记录的这些RTP包transport sequence number通过base sequence number计算得到
  • recv delta: 8bits,对于"packet received"状态的包,也就是收到的RTP包,在recv delta列表中添加对应的的到达时间间隔信息,用于记录RTP包到达时间信息。通过前面的reference time以及recv delta信息,我们就可以得到RTP包到达时间

packet chunk

  • 首先先了解下RTP包状态,目前定义了如下四种状态,每个状态值2bits,用来标识RTP包的到达状态,以及与前面RTP包的时间间隔大小信息:

  • 00-Packet not received
  • 01-Packet received, small delta
  • 10-Packet received, large or negative delta
  • 11-[Reserved]

packet chunk有两种类型,Run length chunk(行程长度编码数据块)与Status vector chunk(状态矢量编码数据块),对应packet chunk结构的两种编码方式。packet chunk的第一bit标识chunk类型。

这里先来了解下Run length(行程长度)编码。Run length编码是一种简单的数据压缩算法,其基本思想是将重复且连续出现多次的字符使用“连续出现次数+字符”来描述,例如:aaabbbcdddd通过Run length编码就可以压缩为3a3bc4d。Run length chunk中就使用了Run length编码标识连续多个相同状态的包。

Run length chunk第一bit为0,后面跟着packet status以及run length。格式如下:

       0                   1

       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5

      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

      |T| S |       Run Length        |

      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

hunk type (T):1 bit,值为0
packet status symbol (S):2 bits,标识包状态
run length (L):13 bits,行程长度,标识有多少个连续包为相同状态

下面举例子说明下。

       0                   1

       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5

      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

      |0|0 0|0 0 0 0 0 1 1 0 1 1 1 0 1|

      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

packet status为00,由前面包状态可知为"Packet not received"状态,run lengh为221(11011101),说明连续有221个包为"Packet not received"状态。

Status Vector Chunk

第一bit为1,后面跟着symbol size以及symbol list。格式如下:

        0                   1

        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5

       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

       |T|S|       symbol list         |

       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

  • chunk type (T):1 bit,值为1
  • symbol size(S):1 bit,为0表示只包含"packet not received" (0)以及"packet received"(1)状态,每个状态使用1bit表示,这样后面14bits的symbol list能标识14个包的状态。为1表示使用2bits来标识包状态,这样symbol list中我们只能标识7个包的状态
  • symbol list:14 bits,标识一系列包的状态, 总共能标识7或14个包的状态

2

3

4

5

        0                   1

        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5

       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

       |1|0|0 1 1 1 1 1 0 0 0 1 1 1 0 0|

       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

symbol size为0,这样能标识14个包的状态。第一个包状态为"packet not received"(0),接着后面5个包状态为"packet received"(1),再接着三个包状态为"packet not received",再接着三个包状态为"packet received",最后两个包状态为"packet not received"。

1

2

3

4

5

        0                   1

        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5

       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

       |1|1|0 0 1 1 0 1 0 1 0 1 0 0 0 0|

       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

symbol size为1,这样只能标识7个包的状态。第一个包为"packet not received"(00)状态,第二个包为 "packet received, w/o timestamp"(11)状态,再接着三个包为"packet received"(01)状态,最后两个包为"packet not received"(00)状态。

Receive Delta

以250us(0.25ms)为单位,表示RTP包到达时间与前面一个RTP包到达时间的间隔,对于记录的第一个RTP包,该包的时间间隔是相对reference time的。

  • 如果在packet chunk记录了一个"Packet received, small delta"状态的包,那么就会在receive delta列表中添加一个无符号1字节长度receive delta,无符号1字节取值范围[0,255],由于Receive Delta以0.25ms为单位,故此时Receive Delta取值范围[0, 63.75]ms
  • 如果在packet chunk记录了一个"Packet received, large or negative delta"状态的包,那么就会在receive delta列表中添加一个有符号2字节长度的receive delta,范围[-8192.0, 8191.75] ms
  • 如果时间间隔超过了最大限制,那么就会构建一个新的TransportFeedback RTCP包,由于reference time长度为3字节,所以目前的包中3字节长度能够覆盖很大范围了

以上说明总结起来就是:对于收到的RTP包在TransportFeedback RTCP receive delta列表中通过时间间隔记录到达时间,如果与前面包时间间隔小,那么使用1字节表示,否则2字节,超过最大取值范围,就另起新RTCP包了。

对于"Packet received, small delta"状态的包来说,receive delta最大值63.75ms,那么一秒时间跨度最少能标识1000/63.75~=16个包。由于receive delta为250us的倍数,所以一秒时间跨度最多能标识4000个包。

packet chunk以及receive delta的使用是为了尽可能减小RTCP包大小。packet chunk用到了不同编码方式,对于收到的RTP包才添加到达时间信息,而且是通过时间间隔的方式记录到达时间。

有关RTCP协议详解(SR、RR、SDES、BYE、APP、NACK、TCC、PLI、SLI、FIR )的更多相关文章

  1. ruby-on-rails - 每次我尝试部署时,我都会得到 - (gcloud.preview.app.deploy) 错误响应 : [4] DEADLINE_EXCEEDED - 2

    我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie

  2. ruby-on-rails - 如何重命名或移动 Rails 的 README_FOR_APP - 2

    当我在我的Rails应用程序根目录中运行rakedoc:app时,API文档是使用/doc/README_FOR_APP作为主页生成的。我想向该文件添加.rdoc扩展名,以便它在GitHub上正确呈现。更好的是,我想将它移动到应用程序根目录(/README.rdoc)。有没有办法通过修改包含的rake/rdoctask任务在我的Rakefile中执行此操作?是否有某个地方可以查找可以修改的主页文件的名称?还是我必须编写一个新的Rake任务?额外的问题:Rails应用程序的两个单独文件/README和/doc/README_FOR_APP背后的逻辑是什么?为什么不只有一个?

  3. ruby - 使用 postgres.app 在 rvm 下要求 pg 时出错 - 2

    我正在使用Postgres.app在OSX(10.8.3)上。我已经修改了我的PATH,以便应用程序的bin文件夹位于所有其他文件夹之前。Rammy:~phrogz$whichpg_config/Applications/Postgres.app/Contents/MacOS/bin/pg_config我已经安装了rvm并且可以毫无错误地安装pggem,但是当我需要它时我得到一个错误:Rammy:~phrogz$gem-v1.8.25Rammy:~phrogz$geminstallpgFetching:pg-0.15.1.gem(100%)Buildingnativeextension

  4. ruby - 为 capybara 设置 app_host 的内容 - 2

    我的测试尝试访问网页并验证页面上是否存在某些元素。例如,它访问http://foo.com/homepage.html并检查Logo图像,然后访问http://bar.com/store/blah.html并检查页面上是否出现了某些文本。我的目标是访问经过Kerberos身份验证的网页。我发现Kerberos代码如下:主文件uri=URI.parse(Capybara.app_host)kerberos=Kerberos.new(uri.host)@kerberos_token=kerberos.encoded_tokenkerberos.rb文件classKerberosdefini

  5. 物联网MQTT协议详解 - 2

    一、什么是MQTT协议MessageQueuingTelemetryTransport:消息队列遥测传输协议。是一种基于客户端-服务端的发布/订阅模式。与HTTP一样,基于TCP/IP协议之上的通讯协议,提供有序、无损、双向连接,由IBM(蓝色巨人)发布。原理:(1)MQTT协议身份和消息格式有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。MQTT传输的消息分为:主题(Topic)和负载(payload)两部分Topic,可以理解为消息的类型,订阅者订阅(Su

  6. Tcl脚本入门笔记详解(一) - 2

    TCL脚本语言简介•TCL(ToolCommandLanguage)是一种解释执行的脚本语言(ScriptingLanguage),它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。•实际上包含了两个部分:一个语言和一个库。首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。由于TCL的解释器是用C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL看作C库,这个库中有丰富的用于扩展TCL命令的C\C++过程和函数,所以,Tcl是

  7. ruby - 导轨 3 : Creating app with internal plugin system - 2

    我想在Rails中使用插件系统创建一个应用程序。潜在用户应该能够上传(或更好地从存储库安装)一个插件并安装它,使我的应用程序能够做更多的事情。这应该在没有FTP/SSH/对服务器的任何低级别访问的情况下完成。关于如何在Rails3中完成它,是否有任何好的gems或教程? 最佳答案 你看过http://edgeguides.rubyonrails.org/plugins.html了吗??它似乎不是100%兼容Rails3,但它可以帮助您入门。我看过的大多数插件文章都涉及Rails2。 关于

  8. ruby - 使用 Foreman 启动位于不同目录的 Rack App - 2

    我有一个成功运行多个进程的Procfile设置:#/Procfileredis:bundleexecredis-serversidekiq:bundleexecsidekiq-v-C./config.ymlforward:forward4567mock-api我需要再添加一个进程-一个位于我机器上不同目录中的Sinatra应用程序。如果我cd到该目录,我可以从终端启动它:$rackup-p4567我可以使用终端从不同的目录启动它:$sh-c'cd/Path/to/project/&&execrackup-p4567'但是我应该如何使用工头来做到这一点。我尝试添加以下内容,但它无声地失败

  9. 【详解】Docker安装Elasticsearch7.16.1集群 - 2

    开门见山|拉取镜像dockerpullelasticsearch:7.16.1|配置存放的目录#存放配置文件的文件夹mkdir-p/opt/docker/elasticsearch/node-1/config#存放数据的文件夹mkdir-p/opt/docker/elasticsearch/node-1/data#存放运行日志的文件夹mkdir-p/opt/docker/elasticsearch/node-1/log#存放IK分词插件的文件夹mkdir-p/opt/docker/elasticsearch/node-1/plugins若你使用了moba,直接右键新建即可如上图所示依次类推创建

  10. 【Elasticsearch基础】Elasticsearch索引、文档以及映射操作详解 - 2

    文章目录概念索引相关操作创建索引更新副本查看索引删除索引索引的打开与关闭收缩索引索引别名查询索引别名文档相关操作新建文档查询文档更新文档删除文档映射相关操作查询文档映射创建静态映射创建索引并添加映射概念es中有三个概念要清楚,分别为索引、映射和文档(不用死记硬背,大概有个印象就可以)索引可理解为MySQL数据库;映射可理解为MySQL的表结构;文档可理解为MySQL表中的每行数据静态映射和动态映射上面已经介绍了,映射可理解为MySQL的表结构,在MySQL中,向表中插入数据是需要先创建表结构的;但在es中不必这样,可以直接插入文档,es可以根据插入的文档(数据),动态的创建映射(表结构),这就

随机推荐