流媒体协议:互联网视频分发协议介绍(渐进式、HLS、DASH、HDS、RTMP协议)

前言:

下图是对各协议进行了一个简单对比,后面详细介绍每一个协议。


一.Http渐进式:

首先,从传输方式上大致可以分为文件下载、HTTP渐进式下载、HTTP流式传输、实时流媒体传输四大类。

渐进式下载是通过在下载仍在执行时播放文件的已下载部分来传递媒体(边下载边播放)。支持Seek,终端播放器可从没下载完成部分中任意选取一个时间点开始播放,如此来满足不用等整个文件下载完快速播放的需求,一般MP4和FLV格式文件支持较好,打开一个视频拖拽到中部,短暂缓冲即可播放,点击暂停后文件仍将被持续下载就是典型的渐进式下载。

渐进式下载文件是介于下载文件和播放流媒体之间的一种形式。与流媒体相同,在开始播放渐进式下载的文件之前无需将整个文件存储在计算机上。而与流媒体不同的是,在完成播放内容之后,整个渐进式下载的文件会保存在计算机上。

传输方式文件下载http渐进式Http流实时流

传输模式先下载,整个文件下载完成才能使用。边下载,边使用,没有对文件分片边下载边使用,对文件进行了分片,是渐进式的升级建立一个connection,实时传输流信息。

传输结果需下载整个文件,且文件保存在本地。与文件下载的区别是可以从seek后下载,文件也保存本地碎片文件多,占用空间大。播完就扔,无需或只需少量缓存空间。

传输内容整个文件整个文件或文件的一部分。索引文件和分片文件将文件或直播信号编码成实时流格式。

传输类型短连接短连接短连接长连接

传输协议Http/Ftp等Http基于Http的HLS/HDS/DASH等RTMP/RSTP等是实时流控制协议。

点播--索引文件包含所有切片下载地址,依次下载切片文件。建立一个Connection,边下边播,实时传输

直播--实时更新索引文件,根据索引文件下载切片文件建立一个Connection,边放边播,实时更新流。

测试:(某视网Flash直播回看,应该是属于点播)

测试环境:win10 64位

测试平台:chorm

测试频道:cctv1

协议:Http协议渐进式

测试账号:

测试结果:(主意看右边信息)

端口号是8000,不论播放状态还是暂停状态,Response Size始终在增大,seek之后重新下载。

二.HLS协议:

HTTP Live Streaming(缩写是HLS)是一个由苹果公司提出的基于HTTP流媒体网络传输协议

HLS架构

相关模块:

Media encoder:用于将设备输出的流进行转码,并封装成MPEG-2传输流。

Stream segmenter:用于直播,将MPEG-2流分割成多个小片段后输出(m3u8和ts切片)。

File segmenter:用于点播,将MPEG-2流分割成多个小片段后输出(m3u8和ts切片)。

 原理:

简单讲就是把整个流分成一个个小段,基于 HTTP 的文件来下载,每次只下载一些,传输内容包括两部分:一是m3u8纯文本索引文件,二是TS媒体文件。简单的传输方式就是在一个m3u8中包含ts切片的url列表,依次下载播放。如下图所示:

还有就是有多级索引,如下图所示,客户端先下载一级Index file,它里面记录了二级索引文件(Alternate-A、Alternate-B、Alternate-C)的地址,然后客户端再去下载二级索引文件,该文件是按照带宽不同划分了不同分辨率的切片文件,然后客户端就可以根据实际的贷款按顺序下载TS视频文件并连续播放以实现码率自适应。

HLS协议传输结构

一般为了加快速度,.m3u8 放在 web 服务器上,ts 文件放在 cdn 上。.m3u8 文件,其实就是以 UTF-8 编码的m3u 文件,这个文件本身不能播放,只是存放了播放信息的文本文件:

HLS协议m3u8文件解析  

标签含义:

      A: #EXTINF指示出下面TS片的时间长度,单位是秒,可以是整数也可以浮点数,浮点数一般精确到小数点后面3位。在示例中,第一个ts的时长为8秒。

同时,EXTINF也影响了播放器刷新M3U8文件的间隔,正常情况下,播放器会把当前下载的TS片的EXTINF的值作为每次刷新M3U8文件的间隔;如果播放器发现本次取到的M3U8文件内容没有更新,会在1-2秒内再次刷新。

B:ts切片的时长不能大于#EXT-X-TARGETDURATION的值

C:#EXT-X-ENDLIST这个表示视频结束,有这个标志同时也说明当前的流是一个非直播流(有结束的意思)。

D:#EXT-X-PLAYLIST-TYPE:VOD的意思是当前的视频流并不是一个直播流,而是点播流。

直播:

1.http 请求 m3u8 的 url(包含部分播放列表,没有结束标识)。

2. 服务端返回一个 m3u8 的播放列表,这个播放列表是实时更新的(类似于滑动窗口机制),一般一次给出5段数据的 url。

3. 客户端解析 m3u8 的播放列表,再按序请求每一段的 url,获取 ts 数据流。

点播:

1.http 请求 m3u8 的 url。(包含所有播放列表,有结束标识)。

2.解析 m3u8 的播放列表,再按序请求每一段的 url,获取 ts 数据流。

备注:hls 协议是将直播流分成一段一段的小段视频去下载播放的,所以假设列表里面的包含5个 ts 文件,每个 TS 文件包含5秒的视频内容,那么整体的延迟就是25秒。因为当你看到这些视频时,已经将视频录制好上传上去了,所以时这样产生的延迟。当然可以缩短列表的长度和单个 ts 文件的大小来降低延迟,极致来说可以缩减列表长度为1,并且 ts 的时长为1s,但是这样会造成请求次数增加,增大服务器压力,当网速慢时回造成更多的缓冲,所以苹果官方推荐的ts时长时10s,所以这样就会大概有30s的延迟。

   弊端:

  1.采用HLS协议直播的视频延迟时间无法下到10秒以下,所以说对直播延迟比较敏感的服务请慎用HLS。(伪直播)。

  2. 对于点播服务来说, 由于 TS 切片通常较小, 海量碎片在文件分发, 一致性缓存, 存储等方面都有较大挑战。

测试:(某视网H5)

测试环境:win10 64位

 测试平台:chorm

 播放器类型:H5

 协议:HLS协议

测试结果:

(测试类型:直播)

M3u8每次更新一个,类似于滑动窗口机制,第一次是列表12345,第二次是23456,第三次事34567,然后按列表地址下载ts切片,直播暂停,m3u8文件继续更新,ts文件停止下载。直播继续播放,继续下载ts切片。下图为央视网直播时连续更新三次m3U8文件的截图:

HLS协议m3u8文件直播时连续更新  

(测试类型:点播)

M3u8一次性包含所有ts文件播放列表,依次进行下载播放,暂停的时候ts切片不下载,播放继续下载,seek进度条的时候,ts切片会从选择位置开始下载。下图为某视网点播seek的ts片段。如下图:

HLS协议m3u8文件点播时seek后ts文件加载图  

三.RTMP协议:

Real Time Message Protocol(RTMP)实时信息传输协议,它是由Adobe公司提出的一种应用层的协议。与HLS等基于Http的其他协议相比,Http协议是本地播放,而RTMP协议是服务器实时播放。

原理:

RTMP传输媒体数据的过程中,服务器端端首先把媒体数据封装成消息,然后把消息分割成消息块,最后将分割后的消息块通过TCP协议发送给客户端。客户端在通过TCP协议收到数据后,首先把消息块重新组合成消息,然后通过对消息进行解封装处理就可以恢复出媒体数据。

RTMP协议规定,播放一个流媒体有几个前提步骤:握手,建立连接,建立流,播放。其中,网络连接代表服务器端应用程序和客户端之间基础的连通关系。网络流代表了发送多媒体数据的通道。服务器和客户端之间只能建立一个网络连接,但是基于该连接可以创建很多网络流。

过程:

1. 握手(HandShake)

一个RTMP连接以握手开始,双方分别发送大小固定的三个数据块

a)握手开始于客户端发送C0、C1块。服务器收到C0或C1后发送S0和S1。

b)当客户端收齐S0和S1后,开始发送C2。当服务器收齐C0和C1后,开始发送S2。

c)当客户端和服务器分别收到S2和C2后,握手完成。

3-1 握手



2.建立网络连接(NetConnection)

a)客户端发送命令消息中的“连接”(connect)到服务器,请求与一个服务应用实例建立连接。

b)服务器接收到连接命令消息后,发送确认窗口大小(Window Acknowledgement Size)协议消息到客户端,同时连接到连接命令中提到的应用程序。

c)服务器发送设置带宽()协议消息到客户端。

d)客户端处理设置带宽协议消息后,发送确认窗口大小(Window Acknowledgement Size)协议消息到服务器端。

e)服务器发送用户控制消息中的“流开始”(Stream Begin)消息到客户端。

f)服务器发送命令消息中的“结果”(_result),通知客户端连接的状态。

3-2 建立连接

3建立网络流(NetStream)

a)客户端发送命令消息中的“创建流”(createStream)命令到服务器端。

b)服务器端接收到“创建流”命令后,发送命令消息中的“结果”(_result),通知客户端流的状态。

3-3 建立流


4 播放(Play)

a)客户端发送命令消息中的“播放”(play)命令到服务器。

b)接收到播放命令后,服务器发送设置块大小(ChunkSize)协议消息。

c)服务器发送用户控制消息中的“streambegin”,告知客户端流ID。

d)播放命令成功的话,服务器发送命令消息中的“响应状态” NetStream.Play.Start & NetStream.Play.reset,告知客户端“播放”命令执行成功。

e)在此之后服务器发送客户端要播放的音频和视频数据。

播放流

结构:

RTMP协议中基本的数据单元称为消息(Message)。当RTMP协议在互联网中传输数据的时候,消息会被拆分成更小的单元,称为消息块(Chunk)。

1 消息

消息是RTMP协议中基本的数据单元。不同种类的消息包含不同的Message Type ID,代表不同的功能。RTMP协议中一共规定了十多种消息类型,分别发挥着不同的作用。例如,Message Type ID在1-7的消息用于协议控制,这些消息一般是RTMP协议自身管理要使用的消息,用户一般情况下无需操作其中的数据。Message Type ID为8,9的消息分别用于传输音频和视频数据。Message Type ID为15-20的消息用于发送AMF编码的命令,负责用户与服务器之间的交互,比如播放,暂停等等。消息首部(Message Header)有四部分组成:标志消息类型的Message Type ID,标志消息长度的Payload Length,标识时间戳的Timestamp,标识消息所属媒体流的Stream ID。消息的报文结构如图3所示。

3-4-1 消息

2 消息块

在网络上传输数据时,消息需要被拆分成较小的数据块,才适合在相应的网络环境上传输。RTMP协议中规定,消息在网络上传输时被拆分成消息块(Chunk)。消息块首部(Chunk Header)有三部分组成:用于标识本块的Chunk Basic Header,用于标识本块负载所属消息的Chunk Message Header,以及当时间戳溢出时才出现的Extended Timestamp。消息块的报文结构如图4所示。


3-4-2 消息块

3 消息分块

在消息被分割成几个消息块的过程中,消息负载部分(Message Body)被分割成大小固定的数据块(默认是128字节,最后一个数据块可以小于该固定长度),并在其首部加上消息块首部(Chunk Header),就组成了相应的消息块。消息分块过程如图5所示,一个大小为307字节的消息被分割成128字节的消息块(除了最后一个)。

3-4-3 消息分块

RTMP传输媒体数据的过程中,发送端首先把媒体数据封装成消息,然后把消息分割成消息块,最后将分割后的消息块通过TCP协议发送出去。接收端在通过TCP协议收到数据后,首先把消息块重新组合成消息,然后通过对消息进行解封装处理就可以恢复出媒体数据。

Audio data包:

RTMP Header:

 1.基本头包括两个信息,Format + Chunk Stream ID。

2.Timestamp:时间戳,3字节。

3.Extended timestamp:当时间值很大 (>= 0x00FFFFFF)时, 上述的Timestamp字段不能传递这样的数值, 因为Timestamp字段只有3个字节,此时需要使用扩展字段Extended Timestamp, 该字段是4个字节。

4.Body size:消息长度,3字节。

5.Type ID:消息类型id,1字节。

6.Stream ID:消息流id,4字节。

Video包Header和audio

RTMP Body:

1.第一个字节af,a就是10,代表AAC编码格式。

2.第一个字节中的后四位f代表如下:

前2个bit的含义采样频率,这里是二进制11,代表44kHZ 的采样频率。

    0 = 5.5 kHz ,1 = 11 kHz ,2 = 22 kHz ,3 = 44 kHz

第3个bit,代表 音频用16位的样本大小。

    0 = 8-bit samples ,1 = 16-bit samples

第4个bit代表声道

    0 = Mono sound(单声道) ,1 = Stereo sound(立体声)

3.第2个字节,AACPacketType,这个字段来表示AACAUDIODATA的类型:0 = AAC sequence header,1 = AAC raw。第一个音频包用0,后面的都用1。

测试:(中国经济网络电视Flash)

测试环境:win10 64位

测试平台:chorm

测试频道:中经电视(http://cen.ce.cn/);宣传生活频道()

协议:RTMP协议

测试账号:

测试结果:

网上搜了一堆RTMP协议测试地址,但是用charles抓包并没有看到明显的有用信息,于是做了很多尝试,为了确定该网站用的是RTMP协议,我先打开了网站视频,用“netstat -aon|findstr “1935””看了一下是否有端口号1935的ip,1935是RTMP协议的端口号,后来我又用WiresShark进行抓包,对RTMP协议请求流程做了验证,实际播放流程跟理论播放流程有一些出入,结果如下图:

以下是宣城经济生活频道的RTMP协议抓包:

对比两个节目,请求流程还是有点不同,所以猜测,两个平台都对RTMP协议做了一定处理。

四.HDS协议:

      Http Dynamic Streaming(HDS)是一个由Adobe公司模仿HLS协议提出的另一个基于Http的流媒体传输协议。其模式跟HLS类似,但是又要比HLS协议复杂一些,也是索引文件和媒体切片文件结合的下载方式。

原理:

     在服务器端降一个视频文件分割成segment节,segment节表示的是这个视频的几种不同的分辨率模式,针对某种分辨率的segment节,可以再划分成fragmen片段,每个片段都是视频的一小段时间,分段后每个片段会有segment+fragment的索引,客户端会根据索引请求视频片段。索引文件可以是.f4m的manifest文件,也可以是.bootstrap文件,在某视网的测试就发现它是采取的后者。

 HDS架构

相关模块:

Live Packager :该工具只针对HDS,同时集成在FMS(3.8以上)。它可以实时测量RTMP流(live),并将之转化成新的\.f4f文件,满足实时性要求。内置的apache服务器使用HTTP ORIGIN MODULE对生成的文件进行解析,然后提供出HTTP流。

File Packager:一个命令行工具,它可以按照需求把多媒体文件形成流碎片并把碎片写进.f4f文件。

HTTP ORIGIN MODULE:HDS的重要组成部分,其为apache的一个modules,负责对(.f4f/.f4m/.f4x/.bootstrap/.drmmeta)等文件进行解析,然后转换成HTTP流输出。

OSMF Player:一个开源的播放器,建立在Open Source Media Framework(OSMF)的框架上,支持HTTP流,要求Flash player 10.1或以上。

文件类型:

 .f4f:分段文件,包含视频数据,每个文件包含源文件的一个分段(segment)。每个segment可以包含更多的碎片(fragment)。每个片段或碎片都有自己的引导信息,提供缓存管理喝快速搜索。播放器可以根据这些信息去请求每个segment或fragment。

.f4m:媒体描述文件,包含媒体的编解码信息,多比特率等等。

.f4x:索引文件,包含指定分片在流中的位置。

.bootstrap:引导文件,引导信息可能来自于bootstrap,也可能来自于.f4m文件(写在bootstrapInfo标签中),取决于是否指定external-bootsrtap选项(Using the bootstrap information (run tables) contained in the file, the client translates the desired timecode to a segment number/fragment number pair. the client then constructs a URL based on this number pair, which requests a specific fragment from a specific F4F file.)

.drmmeta:用于保存加密信息,也需要使用external-bootstrap引用进来。

请求流程:

1.客户端向Web服务器发送一个HTTP请求,例如http://www.example.com/media/http_dynamic_Streaming.f4m

2.服务器将收到的请求传递给HTTP Origin Module。

3.HTTP Origin Module将描述文件(F4M)返回到客户端。

4.客户端收到描述文件(F4M),根据 bootstrap中的信息中的传送时间,组成一个segment#/fragment#对。

5.然后客户端解析F4M的内容向服务器发送一个请求,比如http://www.example.com/media/http_dynamic_StreamingSeg1-Frag1(segment中的fragmen片段)或者http://www.example.com/media/http_dynamic_StreamingSeg1.f4f。(segment)

图. 碎片化内容(F4F)的结构

6.服务器返回相应的视频片段。

7.客户端接收分片,处理之后播放。

标签含义

.bootstrap:

abst: 表示HDS内容的总体信息 adobe bootstrap Info box table

asrt:表示segment总体信息 adobe segment run table

afrt: 表示fragment总体信息 adobe fragment run table

manifest:

StraemType :流类型

BootstrapInfo:引导信息,可以写在标签内,也可以再指定一个url。(上图就是采用了后者)

Media:媒体文件的url或者url的一部分。码率不同,url地址不同。

Mediadata:编解码相关信息。

优势

1.不需要防火墙开普通web浏览器所需端口以外的任何端口

2.允许视频切片在浏览器、网关和CDN的缓存,从而显著降低源服务器的负载。

3.HDS 的文件格式为 FLV/F4V/MP4,索引文件为 f4m,同时支持直播和时移。

测试:(某视网Flash)

测试环境:win10 64位

测试平台:chorm

测试频道:

协议:HDS协议

测试类型:直播

测试结果:

以下是chales抓到的截图:

      测试发现,客户端先请求服务器返回一个时间,然后根据这个时间请求manifest文件,根据manifest文件下载index.bootstrap文件,根据index。Bootstrap文件中的信息,请求分片文件。媒体分片每下载5次,更新一次index.bootstrape文件,不同于HLS协议的是,直播暂停的时候,分片文件停止下载,index.bootstrap文件也停止更新,在视觉上跟点播一样,重新播放也还是能接上上次播放位置,但是暂停时间越长,index.bootstrap文件的更新时间就越久(bootstrap中的分片索引表就越长)。以下是暂停前和播放后更新index.bootstrap中数据的截图:

       虽然看不出数据内容,但可以看出数据长度的变化。这样不停的暂停,与实际直播内容的延时就越来越大,测试发现,当长度到达一定数量,也就是播放内容和实际直播内容的延时达到一定程度,服务器缓存中不存在请求的url,报404错误,客户端会重新请求manfist文件,然后下载index.bootstrap文件,再下载相应切片,跟一开始流程一致。暂时没有找到点播的测试案例。

五.MPEG-DASH协议

Dynamic Adaptive Streaming over HTTP(缩写DASH),是国际标准组MPEG制定的技术标准。

原理:

DASH协议原理跟HLS协议差不多,都是将文件分成一片片小段进行分发,也是分为MPD索引文件和媒体分片文件。客户端首先请求服务器下载解析MPD文件,获取码率等信息,然后根据实际带宽情况去请求某种码率的媒体分片文件以实现自适应切换。MPD 可以以不同的方式,例如SegmentList,SegmentTemplate,SegmentBase和SegmentTimeline,根据使用情况下进行组织。

DASH协议架构
DASH协议传输结构

标签含义:

Period:一条完整的mpeg dash码流可能由一个或多个Peroid组成,每个Period代表一个时间段。比如一个码流是60s,Peroid1是0-10s,Peroid2是11-30,Peroid3是31-60。

Representation:表示不同码率的码流,实际播放的时候,视频会在一个AdaptationSet中的不同Representaiton 之间切换码率,会依次请求该Representaiton下不同Segment序列。

Segment:每一个具体的片段。(1,2,4,6,10s …) 。MPD中描述segment URL的形式有多种,如Segment list,Segment template,Single segment。

AdaptationSet:包含了媒体呈现的形式(视频/音频/字幕),AdaptationSet由一组可供切换的不同码率的码流(Representation)组成。

测试:(TVB)

测试环境:win10 64位

测试平台:chorm

测试频道:翡翠台(https://qa.mytvsuper.com/tc/live/81)

协议:MPEG DASH协议

测试账号:

测试结果:

      (测试类型:点播)

下图是用charles抓取的.mpd数据截图:

视频列表

音频列表

以下是媒体分片的请求列表截图:

测试发现,点播暂停切片文件都不再下载,播放继续下载,广告和视频都是一个文件。Seek后,跳到相应列表位置下载。

观察上图,可以发现规律,比如音频第一个数字后缀是0,第二个是441353,第三个441353 +440294 = 881647正好是初始化后的第二个音频切片文件命的数字后缀部分,就是按照上述列表一次累加,视频的url也是这样。

(测试类型:直播)

测试发现,客户端首先发起一个请求,服务器返回一个session,然后用客户端用这个session请求.mpd文件,根据mpd文件再请求切片文件。

以下是切片的格式:

(字幕)

(音频)

(视频)

Mime type类型注释:

Application:用于传输应用程序数据或者二进制数据;

Audio:用于传输音频或者音声数据;

Video:用于传输动态影像数据,可以是与音频编辑在一起的视频数据格式。

Text:用于标准化地表示的文本信息,文本消息可以是多种字符集和或者多种格式的;

Multipart:用于连接消息体的多个部分构成一个消息,这些部分可以是不同类型的数据;

Message:用于包装一个E-mail消息;

Image:用于传输静态图片数据;

测试中无法确定url数字后缀的第一个值,经多次测试都没有找到SegmentTemplate的明显规律,但累加的值还是按照这个列表,猜测初始值中间可能经过了某种算法,根据点播的测试以及列表的更新情况(mpd更新类似于HLS协议m3u8,每次更新一个)分析,它跟HLS协议的模式应该是相同的。

以下是mpd中更新四次的截图:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容