iOS用Socket自定義協(xié)議寫一套聊天系統(tǒng)(C+S)

前言

我非常佩服那些文章寫的好的人赦政,我想了很久這篇文章應(yīng)該怎么去寫胜宇,名字怎么起,內(nèi)容怎么安排恢着,甚至每個(gè)內(nèi)容深入到什么程度桐愉。寫出來的東西能不能讓大家明白?本著我一貫的風(fēng)格:不光要自己懂掰派,寫出來的文章也要讓別人看懂从诲;我也是這樣來檢測(cè)自己到底是不是真的懂了。所以我會(huì)慢慢的說明靡羡,還請(qǐng)大家花點(diǎn)時(shí)間慢慢看系洛。

寫作原由

2.5年前我有幸成為了一名程序員,從此具備了能改變世界的渺小能力略步。

滑稽.jpg
當(dāng)我興致勃勃的進(jìn)入到第一家公司后我發(fā)現(xiàn)自己什么都改變不了描扯,那時(shí)候的我可以說是一個(gè)隨時(shí)準(zhǔn)備接受教育的咸魚,具體細(xì)節(jié)在這里趟薄,在第一家公司我迅速的成長(zhǎng)了起來绽诚,并有幸得到了一份源碼,6年經(jīng)驗(yàn)的上司全程參與,聊天憔购、推送宫峦、統(tǒng)計(jì)等都是自己做的;我把工程如何啟動(dòng)部分抽離并做成文章分享了出來玫鸟。分享出來后確實(shí)有很多人從中受益导绷,但是更多的是一些負(fù)面評(píng)價(jià),那些負(fù)面評(píng)價(jià)的人我2年后再統(tǒng)一回復(fù)你們:

這個(gè)文章對(duì)于初學(xué)者來說有很明確的指導(dǎo)作用屎飘,告訴初學(xué)者工程目錄結(jié)構(gòu)妥曲、
界面編寫技巧、權(quán)限钦购、職責(zé)檐盟,編碼規(guī)范以及一些值得學(xué)習(xí)的編碼經(jīng)驗(yàn);
但是對(duì)于中高級(jí)程序員來說這文章可能一點(diǎn)用處都沒有押桃,因?yàn)檫@個(gè)階段的程序員大多都有了自己的
一套編程思想葵萎,所以2年之后我再來看這篇文章我也覺得沒啥用,
所以負(fù)面評(píng)價(jià)的人這樣說也是有原因的唱凯。

因?yàn)槟莻€(gè)項(xiàng)目過于龐大羡忘,我也不可能開源出來;那么這篇文章我們就繼續(xù)寫該項(xiàng)目中的另一個(gè)部分:Socket自定義協(xié)議聊天磕昼;當(dāng)然不是從項(xiàng)目中copy出來卷雕,只不過用了該項(xiàng)目中的思路罷了,請(qǐng)你放心這個(gè)項(xiàng)目中的Socket部分已經(jīng)非常成熟票从,目前在三個(gè)項(xiàng)目中運(yùn)行漫雕;也就是說我是有一套完整的聊天源碼的,只是我更希望我能自己慢慢的寫出來峰鄙,去理解當(dāng)中的每一個(gè)點(diǎn)浸间。
很皮.jpg

寫作目的

本身的心愿

其實(shí)早在一年前,我就開始研究聊天部分了先馆,當(dāng)時(shí)很想自己寫一套聊天系統(tǒng)发框;但是當(dāng)時(shí)的技術(shù)實(shí)在太菜,不能理解為什么這樣寫煤墙。一年后我再次研究發(fā)現(xiàn)自己能慢慢看懂了梅惯,在吸收了設(shè)計(jì)思想后我另起Demo打算試試看,了了我的心愿仿野。
沒辦法啊.jpg

提升自己

不知不覺我已經(jīng)擁有2.5年開發(fā)經(jīng)驗(yàn)了铣减,因?yàn)樽约旱墓ぷ鳝h(huán)境,我感覺自己和外面的程序世界斷了聯(lián)系脚作,慢慢發(fā)現(xiàn)自己快要落伍了葫哗;做這個(gè)項(xiàng)目的目的也是為了進(jìn)一步提升自己的技術(shù)缔刹。
有理想的程序員.jpg

給想學(xué)習(xí)Socket的人一個(gè)平臺(tái)

在我學(xué)習(xí)Socket時(shí),我在網(wǎng)上找了一些相關(guān)的文章劣针,比如:
新手入門IM一篇就夠校镐,iOS 即時(shí)通訊,從入門到 “放棄”捺典?等優(yōu)秀的文章鸟廓,對(duì)于一個(gè)不懂Socket聊天的人看了之后都有同樣的困惑:我怎么開始動(dòng)手做呢?是的這些文章要不就是太深無法下手襟己,要不就是太簡(jiǎn)單無法達(dá)到真正工作時(shí)的要求引谜。那么我現(xiàn)在就做了一個(gè)Socket聊天項(xiàng)目,因?yàn)槭?.0.0版本擎浴,所以代碼量非常少员咽,只是把大體的樣子做了出來;相信你從這個(gè)時(shí)候參與項(xiàng)目就能真正的動(dòng)手做了贮预,真正的去實(shí)現(xiàn)一套聊天系統(tǒng)贝室。

無恥.jpg

尋求幫助

自己做一個(gè)聊天系統(tǒng)工作量是非常龐大的,文本仿吞、語音等消息發(fā)送档玻,黑名單等關(guān)系處理,單聊茫藏、群聊、討論組等聊天類型霹琼;所以我需要借助開源的力量务傲,找到一群愿意一起做的人,我們一起商量枣申、設(shè)計(jì)完成整個(gè)系統(tǒng)售葡。整個(gè)系統(tǒng)分為客戶端(文中簡(jiǎn)稱C端)和服務(wù)器端(文中簡(jiǎn)稱S端)

目前聊天系統(tǒng)主要是兩大類
1:CS,也就是有客戶端和服務(wù)器忠藤;
2:P2P挟伙,沒有服務(wù)器客戶端和客戶端直連。
上面兩個(gè)各有各的優(yōu)勢(shì)模孩,P2P主要做局域網(wǎng)聊天尖阔,比如:飛信和飛鴿傳書等;
CS才是目前的主流榨咐,比如:QQ等介却。

S端做消息轉(zhuǎn)發(fā)和存儲(chǔ),S端沒怎么重點(diǎn)設(shè)計(jì)块茁,我考慮用原本的C來充當(dāng)S(主要是我并不會(huì)Node.js等語言齿坷,如果能找到一個(gè)人用Node.js或者其他語言實(shí)現(xiàn)S當(dāng)然是最好的):

1:語言只是工具桂肌;
2:我們的設(shè)計(jì)重心在C端;
3:能知道服務(wù)器的邏輯能幫我們更好的理解整個(gè)聊天過程永淌;
4:C和S都是我們熟悉的OC語言崎场,并不會(huì)有任何語言障礙;
5:每個(gè)人都擁有完整的系統(tǒng)遂蛀,自己方便調(diào)試與開發(fā)谭跨;
6:與其他開發(fā)人員并不產(chǎn)生依賴,完全獨(dú)立答恶。
等待大佬.jpg

如何參與項(xiàng)目

項(xiàng)目1.0.0我已經(jīng)托管到github饺蚊,目前可以這樣參與該項(xiàng)目:1:forkC端S端的源碼,切換到對(duì)應(yīng)的分支進(jìn)行開發(fā):

1:master是可交互的悬嗓、功能完善的主分支污呼;
2:1.0.0dev、1.0.1dev等都是從master分支克隆的包竹,用來進(jìn)行對(duì)應(yīng)版本新功能的開發(fā)燕酷;
這些分支是由我來創(chuàng)建的,你們開發(fā)時(shí)只需要跟蹤當(dāng)前版本就好了周瞎;
3:每個(gè)開發(fā)版本bug修改苗缩、功能開發(fā)完畢后才可合并到主分支,這是一個(gè)小約定声诸;
4:這里并沒有為修改bug單獨(dú)拉取一個(gè)分支酱讶,考慮到復(fù)雜性,盡量減少外界干擾彼乌。

開發(fā)完成后New Push Request泻肯,我來Agreen;2:進(jìn)群(289092194加群理由寫Sokcet學(xué)習(xí)交流慰照,我的個(gè)人信息里面留的群號(hào)是iOS交流群灶挟,你也可以加)一起討論、設(shè)計(jì)和開發(fā)毒租。當(dāng)然了如果確實(shí)沒有人愿意和我一起開發(fā)稚铣,我一個(gè)人也會(huì)堅(jiān)持下去的。對(duì)于要參與本項(xiàng)目的人墅垮,我有以下的幾點(diǎn)要求:

1:代碼要規(guī)范惕医,規(guī)范文檔我已經(jīng)放在項(xiàng)目中了;
這樣做的目的是為了保持風(fēng)格統(tǒng)一噩斟,讓其他人能快速的看懂曹锨;
2:注釋要全,代碼是給人看的剃允;
3:你應(yīng)具備一定的iOS開發(fā)經(jīng)驗(yàn)沛简;
4:盡量寫出可進(jìn)行單元測(cè)試的代碼齐鲤;
5:盡量站在工程師的角度來寫代碼,性能椒楣、速度和內(nèi)存等可適當(dāng)考慮给郊;
6:追求質(zhì)量不追求速度,公司總在趕進(jìn)度捧灰,在這里你可以盡情展示你的代碼給別人看淆九;
7:抱著欣賞的角度去看別人的代碼。

做聊天系統(tǒng)你應(yīng)該知道的知識(shí)點(diǎn)

TCP/IP協(xié)議族

OSI毛俏、TCP/IP.png
網(wǎng)際互聯(lián)層還有其他的叫法:網(wǎng)絡(luò)層等炭庙;
網(wǎng)絡(luò)接口層還有其他的叫法:數(shù)據(jù)鏈路層、鏈路層等煌寇;
大家知道分別指哪一層就好了焕蹄。

我們提到TCP/IP一般就指TCP/IP四層模型,TCP只是傳輸層的一個(gè)協(xié)議阀溶,而IP也只是網(wǎng)際互聯(lián)層的一個(gè)協(xié)議腻脏。TCP/IP是一套定義在硬件層面數(shù)據(jù)傳輸?shù)囊?guī)則,定義這樣一套規(guī)則就是為了讓不同類型數(shù)據(jù)經(jīng)過源地址到目標(biāo)地址中各個(gè)傳輸介質(zhì)時(shí)能差別處理并傳輸罷了银锻。

傳輸協(xié)議選TCP還是UDP

這是一個(gè)必然會(huì)遇到的問題永品,我們?cè)谶@里也不用討論了,多年行業(yè)實(shí)踐經(jīng)驗(yàn)已得出結(jié)論:

1:團(tuán)隊(duì)很牛逼击纬,用UDP或者UDP+TCP鼎姐;
2:團(tuán)隊(duì)一般,用TCP更振。

所以我們用TCP作為我們聊天系統(tǒng)的傳輸協(xié)議症见。

TCP、IP協(xié)議

部分協(xié)議層間使用關(guān)系.png
從這張圖中我們可以看出你用TCP協(xié)議殃饿,那么網(wǎng)絡(luò)層肯定是得用IP協(xié)議了,網(wǎng)絡(luò)接口層用什么協(xié)議需要看情況芋肠,比如有網(wǎng)線乎芳、無網(wǎng)線等;
TCP段.png
IP數(shù)據(jù)報(bào).png
TCP是可靠消息傳輸協(xié)議帖池,頭部定義這么多標(biāo)志位是為了能夠把數(shù)據(jù)盡量送到目的地罷了奈惑。也就是說如果我們用TCP協(xié)議發(fā)送"hello"這個(gè)用戶數(shù)據(jù),那么到了TCP層會(huì)加上TCP頭部組成TCP段睡汹,到了IP層會(huì)加上IP頭部組成IP數(shù)據(jù)報(bào)肴甸,到了網(wǎng)絡(luò)接口層會(huì)加上頭尾部組成幀,這時(shí)候才開始在傳輸介質(zhì)中傳輸囚巴,到達(dá)目的地后每層協(xié)議再剝掉相應(yīng)的首尾部原在,最后得出用戶數(shù)據(jù)"hello"友扰;更復(fù)雜的情況可以看這里

TCP連接時(shí)的三次握手庶柿、四次揮手

這部分請(qǐng)大家看這篇好文村怪,看完之后我來一下總結(jié):

三次握手:當(dāng)我們自己組裝(請(qǐng)注意體會(huì)這個(gè)詞)的TCP段滿足第一次握手格式,發(fā)送到目的地后
浮庐,目的地如果支持TCP連接甚负,那么它就會(huì)回復(fù)你第二次握手的信息,
你收到第二次握手信息再組裝第三次握手格式的TCP段發(fā)送過去就完成了連接操作审残;
四次揮手:道理類似梭域。

為什么需要三次握手和四次揮手請(qǐng)看這里;我們可以像這個(gè)哥們文章一樣自己封裝TCP段模擬三次握手搅轿;當(dāng)然了你也可以了解一下Charles抓取Https原理病涨。

Socket

上面說了我們要用TCP協(xié)議傳遞數(shù)據(jù),就要懂報(bào)介时、段没宾、幀、握手和揮手沸柔,甚至IP分片循衰、超時(shí)重傳滑動(dòng)窗口等,讓我們自己來實(shí)現(xiàn)就太麻煩了褐澎。Socket已經(jīng)幫我們做好了這一切会钝,我們只需要用Socket提供的接口就可以,具體哪些接口可以看這里工三∏ㄋ幔看了這些你可能還是覺得很麻煩。所以才有了CocoaAsyncSocket這個(gè)三方庫俭正,它對(duì)用戶隱藏了麻煩的的Socket操作奸鬓,提供給用戶面向?qū)ο蟮腛C接口;所以本系統(tǒng)也是選用CocoaAsyncSocket進(jìn)行二次封裝掸读。

Socket自定義協(xié)議到底是什么

我們用CocoaAsyncSocket中的GCDAsyncSocket類就可以使用TCP傳輸數(shù)據(jù)串远、GCDAsyncUdpSocket類就可以使用UDP傳輸數(shù)據(jù)了;也就是傳輸控制層及其以下的協(xié)議我們都不可能去自定義了儿惫,那么我們自定義協(xié)議自然就是定義的用戶層協(xié)議澡罚。

實(shí)現(xiàn)聊天目前已存在的常見用戶層協(xié)議

如果你并不想自定義用戶層協(xié)議,那么你可以從這里進(jìn)行已有用戶層協(xié)議選擇肾请,并直接使用提供的SDK進(jìn)行開發(fā)留搔。聊天系統(tǒng)當(dāng)然要分C和S,前面也說了我們的S也是用C來充當(dāng)?shù)模ㄔ俅握f明一下)铛铁。

本系統(tǒng)協(xié)議內(nèi)容部分講解

這里并不會(huì)講太多隔显,因?yàn)樵创a你可以直接下載下來却妨,現(xiàn)在是1.0.0版本代碼量很少,你可以通過寫好的連接荣月、登錄管呵、心跳流程來理解整個(gè)項(xiàng)目?jī)?nèi)容;如果你說看不懂那么你可能還沒有到學(xué)習(xí)Socket的地步哺窄,可以過段時(shí)間再來理解捐下。

說這句話并沒有任何惡意,因?yàn)槿魏问虑槎际且徊揭徊絹淼模?在什么階段學(xué)習(xí)什么內(nèi)容,強(qiáng)行吸收不能掌握的內(nèi)容只會(huì)適得其反。

包格式定義

發(fā)送數(shù)據(jù)時(shí)比如我們發(fā)送一條數(shù)據(jù)"hello world"秃诵,可能目的地前后收到了兩條數(shù)據(jù)"hello "和"world"请毛,因此我們需要進(jìn)行分包處理悔据;分包部分原因:

1:以太網(wǎng)限制在46-1500字節(jié),1500就是以太網(wǎng)的MTU,超過這個(gè)量,TCP會(huì)為IP數(shù)據(jù)報(bào)設(shè)置偏移量
進(jìn)行分片傳輸档叔,現(xiàn)在一般可允許應(yīng)用層設(shè)置8k(NTFS系)的緩沖區(qū),
8k的數(shù)據(jù)由底層分片蒸绩,而應(yīng)用看來只是一次發(fā)送衙四;
2:路由器等也是可以設(shè)置大小的。

發(fā)送數(shù)據(jù)時(shí)比如我們前后發(fā)送兩條數(shù)據(jù)"hello "和"world"患亿,可能目的地只收到了一條數(shù)據(jù)"hello world"传蹈,因此我們需要進(jìn)行粘包處理;粘包部分原因:

1:TCP為提高傳輸效率步藕,發(fā)送方往往要收集到足夠多的數(shù)據(jù)后才發(fā)送
一段數(shù)據(jù)惦界。若連續(xù)幾次發(fā)送的數(shù)據(jù)都很少,通常TCP會(huì)根據(jù)優(yōu)化算法把這些數(shù)據(jù)合成一包后一次發(fā)送出去咙冗,
這樣接收方就收到了粘包數(shù)據(jù)沾歪。

因?yàn)門CP/IP是盡可能提供可靠傳輸,傳輸過程還是可能會(huì)丟包或者接收到錯(cuò)誤的包雾消,所以我們還需要進(jìn)行錯(cuò)包處理瞬逊。針對(duì)這三種問題我們都可以為將發(fā)送數(shù)據(jù)加一個(gè)頭部進(jìn)行解決,可在項(xiàng)目IMSocketHeader中看到仪或;目前只在包頭用4字節(jié)放了4個(gè)標(biāo)志位,每個(gè)標(biāo)志位占1字節(jié):

1:version放用戶當(dāng)前聊天系統(tǒng)版本士骤,用于后面聊天發(fā)布新功能時(shí)范删,舊聊天版本不啟用部分功能等;
2:magic_num用于確定包是不是一個(gè)我們應(yīng)該處理的包拷肌,目前寫死到旦;
3:command存放命令類型區(qū)分心跳旨巷、登錄等,因?yàn)榘煌蛻舳颂硗⒎?wù)器處理方式有很大不同采呐;
4:body_len內(nèi)容長(zhǎng)度,用來處理粘包和分包以可到一個(gè)完整的包搁骑,
具體處理流程在IMSocketIO中看到斧吐。

為啥要進(jìn)進(jìn)行粘包、分包和錯(cuò)誤包處理:

只是為了得到一個(gè)完整的解析單元而已仲器,也就是得到一個(gè)完整的我們定義的包(頭部+內(nèi)容)煤率。

數(shù)據(jù)格式

通過加包頭我們丟給TCP層的數(shù)據(jù)就變成了:包頭+內(nèi)容;那么我們把內(nèi)容以什么樣的格式發(fā)送出去呢乏冀?
這里我們把要發(fā)送的對(duì)象轉(zhuǎn)成JSON字符串再轉(zhuǎn)成NSData進(jìn)行發(fā)送蝶糯。
并沒有選用Protobuf的原因如下:

1:并不是所有想?yún)⑴c項(xiàng)目的人都能順利安裝、使用Protobuf環(huán)境辆沦;
2:數(shù)據(jù)格式在整個(gè)系統(tǒng)設(shè)計(jì)中并不重要昼捍,它更屬于后期優(yōu)化內(nèi)容;
3:對(duì)于JSON我們更為熟悉肢扯,使用起來更快捷方便妒茬。

部分項(xiàng)目中重要的類

其實(shí)目前項(xiàng)目中的連接、登錄等流程已經(jīng)把工程中所有的類都使用完了鹃彻,你可以順藤摸瓜的去走一遍流程就知道各個(gè)類的作用和意義了郊闯。不過還是有幾個(gè)核心類需要單獨(dú)拿出來提一下。

IMSocketModules

需要接收的消息在本類中注冊(cè)蛛株,收到未注冊(cè)的消息內(nèi)部會(huì)自動(dòng)丟棄团赁;這有點(diǎn)像MQTT了。

IMSocketControl

超時(shí)重傳谨履、心跳欢摄、數(shù)據(jù)加解密、收到未注冊(cè)的消息內(nèi)部會(huì)在本類丟棄笋粟。

服務(wù)器項(xiàng)目簡(jiǎn)單介紹

1:采用基礎(chǔ)工程快速搭建怀挠;
2:項(xiàng)目中主要就是一個(gè)類ChatSocketServer用于接收客戶端的連接、登錄害捕、退出绿淋、心跳等請(qǐng)求,之所以用一個(gè)文件因?yàn)楸鞠到y(tǒng)重心是在客戶端尝盼;
3:因?yàn)榱奶焓仟?dú)立于應(yīng)用模塊的吞滞,所以服務(wù)器不做登錄用戶驗(yàn)證,也就是任何登錄信息合法的客戶端進(jìn)行登錄服務(wù)器都會(huì)與之建立連接;
4:數(shù)據(jù)庫用Realm來緩存消息裁赠;
5:版本迭代內(nèi)容在項(xiàng)目中Readme.md中實(shí)時(shí)更新殿漠。

客戶端項(xiàng)目簡(jiǎn)單介紹

1:采用基礎(chǔ)工程快速搭建;
2:目前應(yīng)用中模擬了3個(gè)死用戶佩捞,后期會(huì)考慮注冊(cè)功能绞幌,但是目前用不到;
3:有一個(gè)簡(jiǎn)單的UITabBarController作為主控制器一忱,里面有三個(gè)界面:會(huì)話莲蜘、好友、我掀潮;目前只在我界面展示了用戶信息菇夸,其他的界面后面慢慢迭代;
4:編寫界面時(shí)采用MVC邏輯與視圖完全分離仪吧,可以看看ChatMineController庄新,這也是參照Andoird來寫界面,因?yàn)楸旧砦乙彩且粋€(gè)Android開發(fā)者薯鼠,最近打算試試這樣開發(fā)界面的可行性择诈,當(dāng)然了你參與項(xiàng)目時(shí)你可以在你負(fù)責(zé)的模塊中使用MVP、MVVM等出皇;
5:數(shù)據(jù)庫用Realm羞芍,這樣做可以實(shí)現(xiàn)數(shù)據(jù)庫驅(qū)動(dòng)界面實(shí)時(shí)更新,主要是用了Realm的addNotificationBlock方法郊艘;
6:在SocketIMDemoTests中創(chuàng)建和主工程對(duì)應(yīng)文件夾對(duì)應(yīng)文件進(jìn)行單元測(cè)試荷科;
7:項(xiàng)目使用組件化;
8:版本迭代內(nèi)容在項(xiàng)目中Readme.md中實(shí)時(shí)更新纱注。

文末

我從準(zhǔn)備項(xiàng)目到寫完這篇文章不知不覺過去了半個(gè)月畏浆,這一切都是值得的,至少目前我更了解TCP/IP協(xié)議了狞贱。歡迎大家加群和fork項(xiàng)目刻获,不管你是大牛還是想學(xué)習(xí)的小牛,我們都?xì)g迎你的到來瞎嬉,千萬不要低估了自己的力量蝎毡。
快來.jpg

最壞的情況就是到最后(初步定于2018年3月底開始做1.0.1dev版本)還是只有我一個(gè)人,那么我還是會(huì)堅(jiān)持寫下去的氧枣,只是迭代周期會(huì)長(zhǎng)很多沐兵。

問題反饋區(qū)

在項(xiàng)目發(fā)起后一周,已經(jīng)陸續(xù)有20人參與進(jìn)來便监,參與過程中問題也是很多的扎谎,所以專門在這里記錄下來

怎么運(yùn)行項(xiàng)目?

因?yàn)轫?xiàng)目采用的是組件化,設(shè)置的工程依賴簿透,所以你每次拉取代碼后最好都做一下如下的操作:

1:Clean工程;
2:依次編譯Common解藻、IMServer老充、ModelManager、HttpServer和SocketIMDemo螟左。
3:Run工程啡浊。

運(yùn)行時(shí)Realm報(bào)錯(cuò)

你可能會(huì)遇到下面的錯(cuò)誤
錯(cuò)誤.png

原因:

所有存入Realm數(shù)據(jù)庫的模型,如果有改動(dòng)都需要進(jìn)行升級(jí)胶背,
考慮到開發(fā)過程中模型一直會(huì)不停的變巷嚣,所以我并沒有寫升級(jí)代碼。

解決方案:

卸載重裝應(yīng)用就好了钳吟。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末廷粒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子红且,更是在濱河造成了極大的恐慌坝茎,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件暇番,死亡現(xiàn)場(chǎng)離奇詭異嗤放,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)壁酬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門次酌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人舆乔,你說我怎么就攤上這事岳服。” “怎么了蜕煌?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵派阱,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我斜纪,道長(zhǎng)贫母,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任盒刚,我火速辦了婚禮腺劣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘因块。我一直安慰自己橘原,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著趾断,像睡著了一般拒名。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上芋酌,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天增显,我揣著相機(jī)與錄音,去河邊找鬼脐帝。 笑死同云,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的堵腹。 我是一名探鬼主播炸站,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼疚顷!你這毒婦竟也來了旱易?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤荡含,失蹤者是張志新(化名)和其女友劉穎咒唆,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體释液,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡全释,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了误债。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浸船。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖寝蹈,靈堂內(nèi)的尸體忽然破棺而出李命,到底是詐尸還是另有隱情,我是刑警寧澤箫老,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布封字,位于F島的核電站,受9級(jí)特大地震影響耍鬓,放射性物質(zhì)發(fā)生泄漏阔籽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一牲蜀、第九天 我趴在偏房一處隱蔽的房頂上張望笆制。 院中可真熱鬧,春花似錦涣达、人聲如沸在辆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽匆篓。三九已至浑度,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鸦概,已是汗流浹背俺泣。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留完残,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓横漏,卻偏偏與公主長(zhǎng)得像谨设,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子缎浇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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