RTMP協(xié)議解析(一) —— 基本了解

版本記錄

版本號(hào) 時(shí)間
V1.0 2017.09.04

前言

大家都知道很多視頻應(yīng)用的app中都是使用RTMP格式的協(xié)議,這個(gè)是國際上共同使用的協(xié)議,我自己雖然做過了直播類型的app,但是從沒時(shí)間深入的了解這個(gè)協(xié)議的基礎(chǔ),從這一篇開始讓我們逐步揭開RTMP協(xié)議的神秘面紗,從應(yīng)用層逐步進(jìn)入原理層和底層。

定義

以下內(nèi)容部分來自百度百科

RTMP是Real Time Messaging Protocol(實(shí)時(shí)消息傳輸協(xié)議)的首字母縮寫。該協(xié)議基于TCP,是一個(gè)協(xié)議族,包括RTMP基本協(xié)議及RTMPT/RTMPS/RTMPE等多種變種。RTMP是一種設(shè)計(jì)用來進(jìn)行實(shí)時(shí)數(shù)據(jù)通信的網(wǎng)絡(luò)協(xié)議,主要用來在Flash/AIR平臺(tái)和支持RTMP協(xié)議的流媒體/交互服務(wù)器之間進(jìn)行音視頻和數(shù)據(jù)通信。支持該協(xié)議的軟件包括Adobe Media Server/Ultrant Media Server/red5等。

RTMP又是Routing Table Maintenance Protocol路由選擇表維護(hù)協(xié)議)的縮寫。 在 AppleTalk 協(xié)議組中,路由選擇表維護(hù)協(xié)議(RTMP,Routing Table Protocol)是一種傳輸層協(xié)議,它在 AppleTalk 路由器中建立并維護(hù)路由選擇表。RTMP 基于路由選擇信息協(xié)議(RIP)。正如 RIP 一樣,RTMP 使用跳數(shù)作為路由計(jì)量標(biāo)準(zhǔn)。一個(gè)數(shù)據(jù)包從源 網(wǎng)絡(luò)發(fā)送到目標(biāo)網(wǎng)絡(luò),必須通過的路由器或其它中間介質(zhì)節(jié)點(diǎn)數(shù)目的計(jì)算結(jié)果即為跳數(shù)。

下面我們看一下兩張?jiān)韴D理解一下。


協(xié)議概述

RTMP(Real Time Messaging Protocol)實(shí)時(shí)消息傳送協(xié)議是Adobe Systems公司為Flash播放器和服務(wù)器之間音頻、視頻和數(shù)據(jù)傳輸 開發(fā)的開放協(xié)議。
它有多種變種:

  • RTMP工作在TCP之上,默認(rèn)使用端口1935;
  • RTMPE在RTMP的基礎(chǔ)上增加了加密功能;
  • RTMPT封裝在HTTP請(qǐng)求之上,可穿透防火墻
  • RTMPS類似RTMPT,增加了TLS/SSL的安全功能。

協(xié)議詳細(xì)介紹

RTMP協(xié)議(Real Time Messaging Protocol)是被Flash用于對(duì)象,視頻,音頻的傳輸。這個(gè)協(xié)議建立在TCP協(xié)議或者輪詢HTTP協(xié)議之上。

RTMP協(xié)議就像一個(gè)用來裝數(shù)據(jù)包的容器,這些數(shù)據(jù)既可以是AMF格式的數(shù)據(jù),也可以是FLV中的視/音頻數(shù)據(jù)。

一個(gè)單一的連接可以通過不同的通道傳輸多路網(wǎng)絡(luò)流,這些通道中的包都是按照固定大小的包傳輸?shù)摹?br> 網(wǎng)絡(luò)連接(Connection)一個(gè)Actionscript連接并播放一個(gè)流的簡單代碼:

var videoInstance:Video = your_video_instance;
var nc:NetConnection = new NetConnection();
var connected:Boolean = nc.connect("rtmp:/localhost/myapp");
var ns:NetStream = new NetStream(nc);
videoInstance.attachVideo(ns);
ns.play("flvName");

默認(rèn)端口為1935


握手請(qǐng)求及應(yīng)答

1. 握手過程

Client → Server:向服務(wù)器發(fā)出握手請(qǐng)求.這不屬于協(xié)議包一部分,該握手請(qǐng)求第一個(gè)字節(jié)為(0×03),其后跟著1536個(gè)字節(jié)。盡管看上去這部分的內(nèi)容對(duì)于RTMP協(xié)議來說并不是至關(guān)重要的,但也不可隨意對(duì)待。

Server → Client :服務(wù)器向客戶端回應(yīng)握手請(qǐng)求,這部分的數(shù)據(jù)仍然不屬于RTMP協(xié)議的部分。該回應(yīng)的起始字節(jié)仍然為(0x03),但是后邊跟著兩個(gè)長度為1536個(gè)字節(jié)(一共為3072字節(jié) )的包塊。第一個(gè)1536塊看上去似乎可以是任意內(nèi)容,甚至好像可以是Null都沒有關(guān)系。第二個(gè)1536的代碼塊,是上一步客戶端向服務(wù)器端發(fā)送的握手請(qǐng)求的內(nèi)容。

Client→Server:把上一步服務(wù)器向客戶端回應(yīng)的第二塊1536個(gè)字節(jié)的數(shù)據(jù)塊

至此客戶端與服務(wù)器端的握手結(jié)束,下面將發(fā)送RTMP協(xié)議的包內(nèi)容。

Client → Server :向服務(wù)器發(fā)送連接包。
Server → Client :服務(wù)器回應(yīng)。

... .... 等等... ...

2. RTMP數(shù)據(jù)類型

0×01 Chunk Size changes the chunk size for packets
0×02 Unknown anyone know this one?
0×03 Bytes Read send every x bytes read by both sides
0×04 Ping ping is a stream control message, has subtypes
0×05 Server BW the servers downstream bw
0×06 Client BW the clients upstream bw
0×07 Unknown anyone know this one?
0×08 Audio Data packet containing audio
0×09 Video Data packet containing video data
0x0A - 0×11 Unknown anyone know?
0×12 Notify an invoke which does not expect a reply
0×13 Shared Object has subtypes
0×14 Invoke like remoting call, used for stream actions too.
Shared Object 數(shù)據(jù)類型
0×01 Connect
0×02 Disconnect
0×03 Set Attribute
0×04 Update Data
0×05 Update Attribute
0×06 Send Message
0×07 Status
0×08 Clear Data
0×09 Delete Data
0x0A Delete Attribute
0x0B
Initial Data

3. RTMP包結(jié)構(gòu)

RTMP包 包含一個(gè)固定長度的包頭和一個(gè)最長為128字節(jié)的包體,包頭可以是下面4種長度的任意一種:12, 8, 4, or 1 byte(s)
第一個(gè)字節(jié)的前兩個(gè)Bit很重要,它決定了包頭的長度,它可以用掩碼0xC0進(jìn)行"與"計(jì)算。下面羅列了可能的包頭長度Bits Header Length

00 12 bytes
01 8 bytes
10 4 bytes
11 1 byte

其實(shí)RTMP包結(jié)構(gòu)就是使用了AMF格式.

下面是一個(gè)關(guān)于客戶端向服務(wù)器端發(fā)送流的流程:

  • Client → Server :發(fā)送一個(gè)創(chuàng)建流的請(qǐng)求
  • Server → Client :返回一個(gè)表示流的索引號(hào)
  • Client → Server :開始發(fā)送
  • Client → Server :發(fā)送視音頻數(shù)據(jù)包(這些包在同一個(gè)頻道(channel)并用流的索引號(hào)來唯一標(biāo)識(shí))

4. RTMP Chunk Stream - RTMP塊流

Chunk Stream是對(duì)傳輸RTMP Chunk的流的邏輯上的抽象,客戶端和服務(wù)器之間有關(guān)RTMP的信息都在這個(gè)流上通信。這個(gè)流上的操作也是我們關(guān)注RTMP協(xié)議的重點(diǎn)

Message

Message是指滿足該協(xié)議格式的、可以切分成Chunk發(fā)送的消息,消息包含的字段如下所示。

  • Timestamp(時(shí)間戳):消息的時(shí)間戳(但不一定是當(dāng)前時(shí)間,后面會(huì)介紹),4個(gè)字節(jié)。
  • Length(長度):是指Message Payload(消息負(fù)載)即音視頻等信息的數(shù)據(jù)的長度,3個(gè)字節(jié)。
  • TypeId(類型Id):消息的類型Id,1個(gè)字節(jié)。
  • Message Stream ID(消息的流ID):每個(gè)消息的唯一標(biāo)識(shí),劃分成Chunk和還原Chunk為Message的時(shí)候都是根據(jù)這個(gè)ID來辨識(shí)是否是同一個(gè)消息的Chunk的,4個(gè)字節(jié),并且以小端格式存儲(chǔ)。

Chunking(Message分塊)

RTMP在收發(fā)數(shù)據(jù)的時(shí)候并不是以Message為單位的,而是把Message拆分成Chunk發(fā)送,而且必須在一個(gè)Chunk發(fā)送完成之后才能開始發(fā)送下一個(gè)Chunk。每個(gè)Chunk中帶有MessageID代表屬于哪個(gè)Message,接受端也會(huì)按照這個(gè)id來將chunk組裝成Message。

為什么RTMP要將Message拆分成不同的Chunk呢?通過拆分,數(shù)據(jù)量較大的Message可以被拆分成較小的“Message”,這樣就可以避免優(yōu)先級(jí)低的消息持續(xù)發(fā)送阻塞優(yōu)先級(jí)高的數(shù)據(jù),比如在視頻的傳輸過程中,會(huì)包括視頻幀,音頻幀和RTMP控制信息,如果持續(xù)發(fā)送音頻數(shù)據(jù)或者控制數(shù)據(jù)的話可能就會(huì)造成視頻幀的阻塞,然后就會(huì)造成看視頻時(shí)最煩人的卡頓現(xiàn)象。同時(shí)對(duì)于數(shù)據(jù)量較小的Message,可以通過對(duì)Chunk Header的字段來壓縮信息,從而減少信息的傳輸量。

Chunk的默認(rèn)大小是128字節(jié),在傳輸過程中,通過一個(gè)叫做Set Chunk Size的控制信息可以設(shè)置Chunk數(shù)據(jù)量的最大值,在發(fā)送端和接受端會(huì)各自維護(hù)一個(gè)Chunk Size,可以分別設(shè)置這個(gè)值來改變自己這一方發(fā)送的Chunk的最大大小。大一點(diǎn)的Chunk減少了計(jì)算每個(gè)chunk的時(shí)間從而減少了CPU的占用率,但是它會(huì)占用更多的時(shí)間在發(fā)送上,尤其是在低帶寬的網(wǎng)絡(luò)情況下,很可能會(huì)阻塞后面更重要信息的傳輸。小一點(diǎn)的Chunk可以減少這種阻塞問題,但小的Chunk會(huì)引入過多額外的信息(Chunk中的Header),少量多次的傳輸也可能會(huì)造成發(fā)送的間斷導(dǎo)致不能充分利用高帶寬的優(yōu)勢,因此并不適合在高比特率的流中傳輸。在實(shí)際發(fā)送時(shí)應(yīng)對(duì)要發(fā)送的數(shù)據(jù)用不同的Chunk Size去嘗試,通過抓包分析等手段得出合適的Chunk大小,并且在傳輸過程中可以根據(jù)當(dāng)前的帶寬信息和實(shí)際信息的大小動(dòng)態(tài)調(diào)整Chunk的大小,從而盡量提高CPU的利用率并減少信息的阻塞機(jī)率。

Chunk Format - Chunk格式

下面就說一下快格式里面的組成。

  • Basic Header:它是基本的頭信息。

包含了chunk stream ID(流通道Id)和chunk type(chunk的類型),chunk stream id一般被簡寫為CSID,用來唯一標(biāo)識(shí)一個(gè)特定的流通道,chunk type決定了后面Message Header的格式。Basic Header的長度可能是1,2,或3個(gè)字節(jié),其中chunk type的長度是固定的(占2位,注意單位是位,bit),Basic Header的長度取決于CSID的大小,在足夠存儲(chǔ)這兩個(gè)字段的前提下最好用盡量少的字節(jié)從而減少由于引入Header增加的數(shù)據(jù)量。

RTMP協(xié)議支持用戶自定義[3,65599]之間的CSID,0,1,2由協(xié)議保留表示特殊信息。

0代表Basic Header總共要占用2個(gè)字節(jié),CSID在[64,319]之間;
1代表占用3個(gè)字節(jié),CSID在[64,65599]之間;
2代表該chunk是控制信息和一些命令信息,后面會(huì)有詳細(xì)的介紹。

chunk type的長度固定為2位,因此CSID的長度是(6=8-2)、(14=16-2)、(22=24-2)中的一個(gè)。
當(dāng)Basic Header為1個(gè)字節(jié)時(shí),CSID占6位,6位最多可以表示64個(gè)數(shù),因此這種情況下CSID在[0,63]之間,其中用戶可自定義的范圍為[3,63]。

下面看一下Basic Header不同字節(jié)時(shí)的字節(jié)示意圖。

Basic Header為1個(gè)字節(jié)時(shí)
Basic Header為2或3個(gè)字節(jié)時(shí)

需要注意的是,Basic Header是采用小端存儲(chǔ)的方式,越往后的字節(jié)數(shù)量級(jí)越高。可以看到2個(gè)字節(jié)和3個(gè)字節(jié)的Basic Header所能表示的CSID是有交集的[64,319],但實(shí)際實(shí)現(xiàn)時(shí)還是應(yīng)該秉著最少字節(jié)的原則使用2個(gè)字節(jié)的表示方式來表示[64,319]CSID

  • Message Header

包含了要發(fā)送的實(shí)際信息(可能是完整的,也可能是一部分)的描述信息。Message Header的格式和長度取決于Basic Headerchunk type,共有4種不同的格式,由上面所提到的Basic Header中的fmt字段控制。其中第一種格式可以表示其他三種表示的所有數(shù)據(jù),但由于其他三種格式是基于對(duì)之前chunk的差量化的表示,因此可以更簡潔地表示相同的數(shù)據(jù),實(shí)際使用的時(shí)候還是應(yīng)該采用盡量少的字節(jié)表示相同意義的數(shù)據(jù)。以下按照字節(jié)數(shù)從多到少的順序分別介紹這4種格式的Message Header

(1) type=0時(shí)Message Header占用11個(gè)字節(jié),其他三種能表示的數(shù)據(jù)它都能表示,但在chunk stream的開始的第一個(gè)chunk和頭信息中的時(shí)間戳后退(即值與上一個(gè)chunk相比減小,通常在回退播放的時(shí)候會(huì)出現(xiàn)這種情況)的時(shí)候必須采用這種格式。

Message Header type 0

(2) type=1時(shí)Message Header占用7個(gè)字節(jié),省去了表示msg stream id的4個(gè)字節(jié),表示此chunk和上一次發(fā)的chunk所在的流相同,如果在發(fā)送端只和對(duì)端有一個(gè)流鏈接的時(shí)候可以盡量去采取這種格式。

Message Header type 1

(3) type=2時(shí)Message Header占用3個(gè)字節(jié),相對(duì)于type=1格式又省去了表示消息長度的3個(gè)字節(jié)和表示消息類型的1個(gè)字節(jié),表示此chunk和上一次發(fā)送的chunk所在的流、消息的長度和消息的類型都相同。余下的這三個(gè)字節(jié)表示timestamp delta,使用同type=1 。

Message Header type 2

(4) 0字節(jié)!!!好吧,它表示這個(gè)chunk的Message Header和上一個(gè)是完全相同的,自然就不用再傳輸一遍了。當(dāng)它跟在Type=0的chunk后面時(shí),表示和前一個(gè)chunk的時(shí)間戳都是相同的。什么時(shí)候連時(shí)間戳都相同呢?就是一個(gè)Message拆分成了多個(gè)chunk,這個(gè)chunk和上一個(gè)chunk同屬于一個(gè)Message。而當(dāng)它跟在Type=1或者Type=2的chunk后面時(shí),表示和前一個(gè)chunk的時(shí)間戳的差是相同的。比如第一個(gè)chunk的Type=0,timestamp=100,第二個(gè)chunk的Type=2,timestamp delta=20,表示時(shí)間戳為100+20=120,第三個(gè)chunk的Type=3,表示timestamp delta=20,時(shí)間戳為120+20=140。

  • Extended Timestamp(擴(kuò)展時(shí)間戳)

上面我們提到在chunk中會(huì)有時(shí)間戳timestamp和時(shí)間戳差timestamp delta,并且它們不會(huì)同時(shí)存在,只有這兩者之一大于3個(gè)字節(jié)能表示的最大數(shù)值0xFFFFFF=16777215時(shí),才會(huì)用這個(gè)字段來表示真正的時(shí)間戳,否則這個(gè)字段為0。擴(kuò)展時(shí)間戳占4個(gè)字節(jié),能表示的最大數(shù)值就是0xFFFFFFFF=4294967295。當(dāng)擴(kuò)展時(shí)間戳啟用時(shí),timestamp字段或者timestamp delta要全置為1,表示應(yīng)該去擴(kuò)展時(shí)間戳字段來提取真正的時(shí)間戳或者時(shí)間戳差。注意擴(kuò)展時(shí)間戳存儲(chǔ)的是完整值,而不是減去時(shí)間戳或者時(shí)間戳差的值。

  • Chunk Data(塊數(shù)據(jù)):

用戶層面上真正想要發(fā)送的與協(xié)議無關(guān)的數(shù)據(jù),長度在[0,chunkSize]之間。

協(xié)議控制消息(Protocol Control Message)

在RTMP的chunk流會(huì)用一些特殊的值來代表協(xié)議的控制消息,它們的Message Stream ID必須為0(代表控制流信息),CSID必須為2,Message Type ID可以為1,2,3,5,6,具體代表的消息會(huì)在下面依次說明。控制消息的接受端會(huì)忽略掉chunk中的時(shí)間戳,收到后立即生效。

  • Set Chunk Size(Message Type ID=1):設(shè)置chunk中Data字段所能承載的最大字節(jié)數(shù),默認(rèn)為128B,通信過程中可以通過發(fā)送該消息來設(shè)置chunk Size的大小(不得小于128B),而且通信雙方會(huì)各自維護(hù)一個(gè)chunkSize,兩端的chunkSize是獨(dú)立的。

  • Abort Message(Message Type ID=2):當(dāng)一個(gè)Message被切分為多個(gè)chunk,接受端只接收到了部分chunk時(shí),發(fā)送該控制消息表示發(fā)送端不再傳輸同Message的chunk,接受端接收到這個(gè)消息后要丟棄這些不完整的chunk。Data數(shù)據(jù)中只需要一個(gè)CSID,表示丟棄該CSID的所有已接收到的chunk。

  • Acknowledgement(Message Type ID=3):當(dāng)收到對(duì)端的消息大小等于窗口大小(Window Size)時(shí)接受端要回饋一個(gè)ACK給發(fā)送端告知對(duì)方可以繼續(xù)發(fā)送數(shù)據(jù)。窗口大小就是指收到接受端返回的ACK前最多可以發(fā)送的字節(jié)數(shù)量,返回的ACK中會(huì)帶有從發(fā)送上一個(gè)ACK后接收到的字節(jié)數(shù)。

  • Window Acknowledgement Size(Message Type ID=5):發(fā)送端在接收到接受端返回的兩個(gè)ACK間最多可以發(fā)送的字節(jié)數(shù)。

  • Set Peer Bandwidth(Message Type ID=6):限制對(duì)端的輸出帶寬。接受端接收到該消息后會(huì)通過設(shè)置消息中的Window ACK Size來限制已發(fā)送但未接受到反饋的消息的大小來限制發(fā)送端的發(fā)送帶寬。如果消息中的Window ACK Size與上一次發(fā)送給發(fā)送端的size不同的話要回饋一個(gè)Window Acknowledgement Size的控制消息。

(1)Hard(Limit Type=0):接受端應(yīng)該將Window Ack Size設(shè)置為消息中的值
(2)Soft(Limit Type=1):接受端可以講Window Ack Size設(shè)為消息中的值,也可以保存原來的值(前提是原來的Size小與該控制消息中的Window Ack Size
(3)Dynamic(Limit Type=2):如果上次的Set Peer Bandwidth消息中的Limit Type為0,本次也按Hard處理,否則忽略本消息,不去設(shè)置Window Ack Size

5. 不同類型的RTMP Message

  • Command Message(命令消息,Message Type ID=17或20):表示在客戶端和服務(wù)器間傳遞的在對(duì)端執(zhí)行某些操作的命令消息,如connect表示連接對(duì)端,對(duì)端如果同意連接的話會(huì)記錄發(fā)送端信息并返回連接成功消息,publish表示開始向?qū)Ψ酵屏鳎邮芏私拥矫詈鬁?zhǔn)備好接受對(duì)端發(fā)送的流信息,后面會(huì)對(duì)比較常見的Command Message具體介紹。當(dāng)信息使用AMF0編碼時(shí),Message Type ID=20,AMF3編碼時(shí)Message Type ID=17。
  • Data Message(數(shù)據(jù)消息,Message Type ID=15或18):傳遞一些元數(shù)據(jù)(MetaData,比如視頻名,分辨率等等)或者用戶自定義的一些消息。當(dāng)信息使用AMF0編碼時(shí),Message Type ID=18,AMF3編碼時(shí)Message Type ID=15。
  • Shared Object Message(共享消息,Message Type ID=16或19):表示一個(gè)Flash類型的對(duì)象,由鍵值對(duì)的集合組成,用于多客戶端,多實(shí)例時(shí)使用。當(dāng)信息使用AMF0編碼時(shí),Message Type ID=19,AMF3編碼時(shí)Message Type ID=16
  • Audio Message(音頻信息,Message Type ID=8):音頻數(shù)據(jù)。
  • Video Message(視頻信息,Message Type ID=9):視頻數(shù)據(jù)。
  • Aggregate Message (聚集信息,Message Type ID=22):多個(gè)RTMP子消息的集合 。
  • User Control Message Events(用戶控制消息,Message Type ID=4):告知對(duì)方執(zhí)行該信息中包含的用戶控制事件,比如Stream Begin事件告知對(duì)方流信息開始傳輸。和前面提到的協(xié)議控制信息(Protocol Control Message)不同,這是在RTMP協(xié)議層的,而不是在RTMP chunk流協(xié)議層的,這個(gè)很容易弄混。該信息在chunk流中發(fā)送時(shí),Message Stream ID=0,Chunk Stream Id=2,Message Type Id=4

6. 基于RTMP協(xié)議的推流和拉流播放過程

先看一下推流過程。

推流過程

再看一下拉流過程

拉流播放過程

參考文章

1. 帶你吃透RTMP

后記

未完,待續(xù)~~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,117評(píng)論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,860評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,128評(píng)論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,291評(píng)論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,025評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,421評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,477評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,642評(píng)論 0 289
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,177評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,970評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,157評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,717評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,410評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,821評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,053評(píng)論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,896評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,157評(píng)論 2 375

推薦閱讀更多精彩內(nèi)容