C語言網(wǎng)絡(luò)編程干貨

我們深諳信息交流的價值巷折,那網(wǎng)絡(luò)中進程之間如何通信甸赃,如我們每天打開瀏覽器瀏覽網(wǎng)頁時瀑罗,瀏覽器的進程怎么與web服務(wù)器通信的闽颇?當(dāng)你用QQ聊天時盾戴,QQ進程怎么與服務(wù)器或你好友所在的QQ進程通信?這些都得靠socket兵多?那什么是socket尖啡?socket的類型有哪些橄仆?還有socket的基本函數(shù),這些都是本文想介紹的可婶。本文的主要內(nèi)容如下:

1沿癞、網(wǎng)絡(luò)中進程之間如何通信?
2矛渴、Socket是什么椎扬?
3、socket的基本操作
    3.1具温、socket()函數(shù)
    3.2蚕涤、bind()函數(shù)
    3.3、listen()铣猩、connect()函數(shù)
    3.4揖铜、accept()函數(shù)
    3.5、read()达皿、write()函數(shù)等
    3.6天吓、close()函數(shù)
4、socket中TCP的三次握手建立連接詳解
5峦椰、socket中TCP的四次握手釋放連接詳解
6龄寞、一個例子(實踐一下)

1、網(wǎng)絡(luò)中進程之間如何通信汤功?

本地的進程間通信(IPC)有很多種方式物邑,但可以總結(jié)為下面4類:

  • 消息傳遞(管道、FIFO滔金、消息隊列)
  • 同步(互斥量色解、條件變量、讀寫鎖餐茵、文件和寫記錄鎖科阎、信號量)
  • 共享內(nèi)存(匿名的和具名的)
  • 遠程過程調(diào)用(Solaris門和Sun RPC)

但這些都不是本文的主題!我們要討論的是網(wǎng)絡(luò)中進程之間如何通信忿族?首要解決的問題是如何唯一標識一個進程萧恕,否則通信無從談起!在本地可以通過進程PID來唯一標識一個進程肠阱,但是在網(wǎng)絡(luò)中這是行不通的。其實TCP/IP協(xié)議族已經(jīng)幫我們解決了這個問題朴读,網(wǎng)絡(luò)層的“ip地址”可以唯一標識網(wǎng)絡(luò)中的主機屹徘,而傳輸層的“協(xié)議+端口”可以唯一標識主機中的應(yīng)用程序(進程)。這樣利用三元組(ip地址衅金,協(xié)議噪伊,端口)就可以標識網(wǎng)絡(luò)的進程了簿煌,網(wǎng)絡(luò)中的進程通信就可以利用這個標志與其它進程進行交互。

使用TCP/IP協(xié)議的應(yīng)用程序通常采用應(yīng)用編程接口:UNIX BSD的套接字(socket)和UNIX System V的TLI(已經(jīng)被淘汰)鉴吹,來實現(xiàn)網(wǎng)絡(luò)進程之間的通信姨伟。就目前而言,幾乎所有的應(yīng)用程序都是采用socket豆励,而現(xiàn)在又是網(wǎng)絡(luò)時代夺荒,網(wǎng)絡(luò)中進程通信是無處不在,這就是我為什么說“一切皆socket”良蒸。

2技扼、什么是Socket?

上面我們已經(jīng)知道網(wǎng)絡(luò)中的進程是通過socket來通信的嫩痰,那什么是socket呢剿吻?socket起源于Unix,而Unix/Linux基本哲學(xué)之一就是“一切皆文件”串纺,都可以用“打開open –> 讀寫write/read –> 關(guān)閉close”模式來操作丽旅。我的理解就是Socket就是該模式的一個實現(xiàn),socket即是一種特殊的文件纺棺,一些socket函數(shù)就是對其進行的操作(讀/寫IO榄笙、打開、關(guān)閉)五辽,這些函數(shù)我們在后面進行介紹办斑。

socket一詞的起源
在組網(wǎng)領(lǐng)域的首次使用是在1970年2月12日發(fā)布的文獻IETF RFC33中發(fā)現(xiàn)的,撰寫者為Stephen Carr杆逗、Steve Crocker和Vint Cerf乡翅。根據(jù)美國計算機歷史博物館的記載,Croker寫道:“命名空間的元素都可稱為套接字接口罪郊。一個套接字接口構(gòu)成一個連接的一端蠕蚜,而一個連接可完全由一對套接字接口規(guī)定』陂希”計算機歷史博物館補充道:“這比BSD的套接字接口定義早了大約12年靶累。”

3癣疟、socket的基本操作

既然socket是“open—write/read—close”模式的一種實現(xiàn)挣柬,那么socket就提供了這些操作對應(yīng)的函數(shù)接口。下面以TCP為例睛挚,介紹幾個基本的socket接口函數(shù)邪蛔。

3.1、socket()函數(shù)

int socket(int domain, int type, int protocol);

socket函數(shù)對應(yīng)于普通文件的打開操作扎狱。普通文件的打開操作返回一個文件描述字侧到,而socket()用于創(chuàng)建一個socket描述符(socket descriptor)勃教,它唯一標識一個socket。這個socket描述字跟文件描述字一樣匠抗,后續(xù)的操作都有用到它故源,把它作為參數(shù),通過它來進行一些讀寫操作汞贸。

正如可以給fopen的傳入不同參數(shù)值绳军,以打開不同的文件。創(chuàng)建socket的時候著蛙,也可以指定不同的參數(shù)創(chuàng)建不同的socket描述符删铃,socket函數(shù)的三個參數(shù)分別為:

  • domain:即協(xié)議域,又稱為協(xié)議族(family)踏堡。常用的協(xié)議族有猎唁,AF_INET、AF_INET6顷蟆、AF_LOCAL(或稱AF_UNIX诫隅,Unix域socket)、AF_ROUTE等等帐偎。協(xié)議族決定了socket的地址類型逐纬,在通信中必須采用對應(yīng)的地址,如AF_INET決定了要用ipv4地址(32位的)與端口號(16位的)的組合削樊、AF_UNIX決定了要用一個絕對路徑名作為地址豁生。
  • type:指定socket類型。常用的socket類型有漫贞,SOCK_STREAM甸箱、SOCK_DGRAM、SOCK_RAW迅脐、SOCK_PACKET芍殖、SOCK_SEQPACKET等等(socket的類型有哪些?)谴蔑。
  • protocol:故名思意豌骏,就是指定協(xié)議。常用的協(xié)議有隐锭,IPPROTO_TCP窃躲、IPPTOTO_UDP、IPPROTO_SCTP钦睡、IPPROTO_TIPC等框舔,它們分別對應(yīng)TCP傳輸協(xié)議、UDP傳輸協(xié)議、STCP傳輸協(xié)議刘绣、TIPC傳輸協(xié)議(這個協(xié)議我將會單獨開篇討論!)挣输。

注意:并不是上面的type和protocol可以隨意組合的纬凤,如SOCK_STREAM不可以跟IPPROTO_UDP組合。當(dāng)protocol為0時撩嚼,會自動選擇type類型對應(yīng)的默認協(xié)議*

當(dāng)我們調(diào)用socket創(chuàng)建一個socket時停士,返回的socket描述字它存在于協(xié)議族(address family,AF_XXX)空間中完丽,但沒有一個具體的地址恋技。如果想要給它賦值一個地址,就必須調(diào)用bind()函數(shù)逻族,否則就當(dāng)調(diào)用connect()蜻底、listen()時系統(tǒng)會自動隨機分配一個端口。

3.2聘鳞、bind()函數(shù)

正如上面所說bind()函數(shù)把一個地址族中的特定地址賦給socket薄辅。例如對應(yīng)AF_INET、AF_INET6就是把一個ipv4或ipv6地址和端口號組合賦給socket抠璃。

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

函數(shù)的三個參數(shù)分別為:

sockfd:即socket描述字站楚,它是通過socket()函數(shù)創(chuàng)建了,唯一標識一個socket搏嗡。bind()函數(shù)就是將給這個描述字綁定一個名字窿春。
addr:一個const struct sockaddr *指針,指向要綁定給sockfd的協(xié)議地址采盒。這個地址結(jié)構(gòu)根據(jù)地址創(chuàng)建socket時的地址協(xié)議族的不同而不同旧乞,如ipv4對應(yīng)的是: 

struct sockaddr_in {
    sa_family_t    sin_family; /* address family: AF_INET */
    in_port_t      sin_port;   /* port in network byte order */
    struct in_addr sin_addr;   /* internet address */
};

/* Internet address. */
struct in_addr {
    uint32_t       s_addr;     /* address in network byte order */
};

ipv6對應(yīng)的是: 

struct sockaddr_in6 { 
    sa_family_t     sin6_family;   /* AF_INET6 */ 
    in_port_t       sin6_port;     /* port number */ 
    uint32_t        sin6_flowinfo; /* IPv6 flow information */ 
    struct in6_addr sin6_addr;     /* IPv6 address */ 
    uint32_t        sin6_scope_id; /* Scope ID (new in 2.4) */ 
};

struct in6_addr { 
    unsigned char   s6_addr[16];   /* IPv6 address */ 
};

Unix域?qū)?yīng)的是: 

#define UNIX_PATH_MAX    108

struct sockaddr_un { 
    sa_family_t sun_family;               /* AF_UNIX */ 
    char        sun_path[UNIX_PATH_MAX];  /* pathname */ 
};

addrlen:對應(yīng)的是地址的長度。

通常服務(wù)器在啟動的時候都會綁定一個眾所周知的地址(如ip地址+端口號)纽甘,用于提供服務(wù)良蛮,客戶就可以通過它來接連服務(wù)器;而客戶端就不用指定悍赢,有系統(tǒng)自動分配一個端口號和自身的ip地址組合决瞳。這就是為什么通常服務(wù)器端在listen之前會調(diào)用bind(),而客戶端就不會調(diào)用左权,而是在connect()時由系統(tǒng)隨機生成一個皮胡。

網(wǎng)絡(luò)字節(jié)序與主機字節(jié)序

主機字節(jié)序就是我們平常說的大端和小端模式:不同的CPU有不同的字節(jié)序類型,這些字節(jié)序是指整數(shù)在內(nèi)存中保存的順序赏迟,這個叫做主機序屡贺。引用標準的Big-Endian和Little-Endian的定義如下:

  • a) Little-Endian就是低位字節(jié)排放在內(nèi)存的低地址端,高位字節(jié)排放在內(nèi)存的高地址端。

  • b) Big-Endian就是高位字節(jié)排放在內(nèi)存的低地址端甩栈,低位字節(jié)排放在內(nèi)存的高地址端泻仙。

  • 網(wǎng)絡(luò)字節(jié)序:4個字節(jié)的32 bit值以下面的次序傳輸:首先是0~7bit,其次8~15bit量没,然后16~23bit玉转,最后是24~31bit。這種傳輸次序稱作大端字節(jié)序殴蹄。由于TCP/IP首部中所有的二進制整數(shù)在網(wǎng)絡(luò)中傳輸時都要求以這種次序究抓,因此它又稱作網(wǎng)絡(luò)字節(jié)序。字節(jié)序袭灯,顧名思義字節(jié)的順序刺下,就是大于一個字節(jié)類型的數(shù)據(jù)在內(nèi)存中的存放順序,一個字節(jié)的數(shù)據(jù)沒有順序的問題了稽荧。

    所以:在將一個地址綁定到socket的時候橘茉,請先將主機字節(jié)序轉(zhuǎn)換成為網(wǎng)絡(luò)字節(jié)序,而不要假定主機字節(jié)序跟網(wǎng)絡(luò)字節(jié)序一樣使用的是Big-Endian蛤克。由于這個問題曾引發(fā)過血案捺癞!公司項目代碼中由于存在這個問題,導(dǎo)致了很多莫名其妙的問題构挤,所以請謹記對主機字節(jié)序不要做任何假定髓介,務(wù)必將其轉(zhuǎn)化為網(wǎng)絡(luò)字節(jié)序再賦給socket。

3.3筋现、listen()唐础、connect()函數(shù)

如果作為一個服務(wù)器,在調(diào)用socket()矾飞、bind()之后就會調(diào)用listen()來監(jiān)聽這個socket一膨,如果客戶端這時調(diào)用connect()發(fā)出連接請求,服務(wù)器端就會接收到這個請求洒沦。

int listen(int sockfd, int backlog);

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

listen函數(shù)的第一個參數(shù)即為要監(jiān)聽的socket描述字豹绪,第二個參數(shù)為相應(yīng)socket可以排隊的最大連接個數(shù)。socket()函數(shù)創(chuàng)建的socket默認是一個主動類型的申眼,listen函數(shù)將socket變?yōu)楸粍宇愋偷穆鹘颍却蛻舻倪B接請求。

connect函數(shù)的第一個參數(shù)即為客戶端的socket描述字括尸,第二參數(shù)為服務(wù)器的socket地址巷蚪,第三個參數(shù)為socket地址的長度”舴客戶端通過調(diào)用connect函數(shù)來建立與TCP服務(wù)器的連接屁柏。

3.4啦膜、accept()函數(shù)

TCP服務(wù)器端依次調(diào)用socket()、bind()淌喻、listen()之后僧家,就會監(jiān)聽指定的socket地址了。TCP客戶端依次調(diào)用socket()、connect()之后就想TCP服務(wù)器發(fā)送了一個連接請求。TCP服務(wù)器監(jiān)聽到這個請求之后规哪,就會調(diào)用accept()函數(shù)取接收請求鸟蜡,這樣連接就建立好了。之后就可以開始網(wǎng)絡(luò)I/O操作了豌注,即類同于普通文件的讀寫I/O操作伤塌。

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

accept函數(shù)的第一個參數(shù)為服務(wù)器的socket描述字,第二個參數(shù)為指向struct sockaddr *的指針轧铁,用于返回客戶端的協(xié)議地址每聪,第三個參數(shù)為協(xié)議地址的長度。如果accpet成功齿风,那么其返回值是由內(nèi)核自動生成的一個全新的描述字药薯,代表與返回客戶的TCP連接。

注意:accept的第一個參數(shù)為服務(wù)器的socket描述字救斑,是服務(wù)器開始調(diào)用socket()函數(shù)生成的童本,稱為監(jiān)聽socket描述字;而accept函數(shù)返回的是已連接的socket描述字脸候。一個服務(wù)器通常通常僅僅只創(chuàng)建一個監(jiān)聽socket描述字穷娱,它在該服務(wù)器的生命周期內(nèi)一直存在。內(nèi)核為每個由服務(wù)器進程接受的客戶連接創(chuàng)建了一個已連接socket描述字运沦,當(dāng)服務(wù)器完成了對某個客戶的服務(wù)泵额,相應(yīng)的已連接socket描述字就被關(guān)閉。

3.5携添、read()嫁盲、write()等函數(shù)

萬事具備只欠東風(fēng),至此服務(wù)器與客戶已經(jīng)建立好連接了烈掠⌒叱樱可以調(diào)用網(wǎng)絡(luò)I/O進行讀寫操作了,即實現(xiàn)了網(wǎng)咯中不同進程之間的通信向叉!網(wǎng)絡(luò)I/O操作有下面幾組:

read()/write()
recv()/send()
readv()/writev()
recvmsg()/sendmsg()
recvfrom()/sendto()

我推薦使用recvmsg()/sendmsg()函數(shù)锥腻,這兩個函數(shù)是最通用的I/O函數(shù),實際上可以把上面的其它函數(shù)都替換成這兩個函數(shù)母谎。它們的聲明如下:

   #include <unistd.h>

   ssize_t read(int fd, void *buf, size_t count);
   ssize_t write(int fd, const void *buf, size_t count);

   #include <sys/types.h>
   #include <sys/socket.h>

   ssize_t send(int sockfd, const void *buf, size_t len, int flags);
   ssize_t recv(int sockfd, void *buf, size_t len, int flags);

   ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                  const struct sockaddr *dest_addr, socklen_t addrlen);
   ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                    struct sockaddr *src_addr, socklen_t *addrlen);

   ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
   ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

read函數(shù)是負責(zé)從fd中讀取內(nèi)容.當(dāng)讀成功時瘦黑,read返回實際所讀的字節(jié)數(shù),如果返回的值是0表示已經(jīng)讀到文件的結(jié)束了,小于0表示出現(xiàn)了錯誤幸斥。如果錯誤為EINTR說明讀是由中斷引起的匹摇,如果是ECONNREST表示網(wǎng)絡(luò)連接出了問題。

write函數(shù)將buf中的nbytes字節(jié)內(nèi)容寫入文件描述符fd.成功時返回寫的字節(jié)數(shù)甲葬。失敗時返回-1廊勃,并設(shè)置errno變量。 在網(wǎng)絡(luò)程序中经窖,當(dāng)我們向套接字文件描述符寫時有兩種可能坡垫。

  • 1)write的返回值大于0,表示寫了部分或者是全部的數(shù)據(jù)画侣。
  • 2)返回的值小于0冰悠,此時出現(xiàn)了錯誤。我們要根據(jù)錯誤類型來處理配乱。如果錯誤為EINTR表示在寫的時候出現(xiàn)了中斷錯誤溉卓。如果為EPIPE表示網(wǎng)絡(luò)連接出現(xiàn)了問題(對方已經(jīng)關(guān)閉了連接)。

其它的我就不一一介紹這幾對I/O函數(shù)了搬泥,具體參見man文檔或者baidu桑寨、Google,下面的例子中將使用到send/recv忿檩。

3.6尉尾、close()函數(shù)

在服務(wù)器與客戶端建立連接之后,會進行一些讀寫操作休溶,完成了讀寫操作就要關(guān)閉相應(yīng)的socket描述字代赁,好比操作完打開的文件要調(diào)用fclose關(guān)閉打開的文件。

include <unistd.h>

int close(int fd);

close一個TCP socket的缺省行為時把該socket標記為以關(guān)閉兽掰,然后立即返回到調(diào)用進程芭碍。該描述字不能再由調(diào)用進程使用,也就是說不能再作為read或write的第一個參數(shù)孽尽。

注意:close操作只是使相應(yīng)socket描述字的引用計數(shù)-1窖壕,只有當(dāng)引用計數(shù)為0的時候,才會觸發(fā)TCP客戶端向服務(wù)器發(fā)送終止連接請求杉女。

4瞻讽、socket中TCP的三次握手建立連接詳解

我們知道tcp建立連接要進行“三次握手”,即交換三個分組熏挎。大致流程如下:

客戶端向服務(wù)器發(fā)送一個SYN J
服務(wù)器向客戶端響應(yīng)一個SYN K速勇,并對SYN J進行確認ACK J+1
客戶端再想服務(wù)器發(fā)一個確認ACK K+1

當(dāng)客戶端調(diào)用connect時,觸發(fā)了連接請求坎拐,向服務(wù)器發(fā)送了SYN J包烦磁,這時connect進入阻塞狀態(tài)养匈;服務(wù)器監(jiān)聽到連接請求,即收到SYN J包都伪,調(diào)用accept函數(shù)接收請求向客戶端發(fā)送SYN K 呕乎,ACK J+1,這時accept進入阻塞狀態(tài)陨晶;客戶端收到服務(wù)器的SYN K 猬仁,ACK J+1之后,這時connect返回先誉,并對SYN K進行確認湿刽;服務(wù)器收到ACK K+1時,accept返回褐耳,至此三次握手完畢叭爱,連接建立。

總結(jié):客戶端的connect在三次握手的第二個次返回漱病,而服務(wù)器端的accept在三次握手的第三次返回。

5把曼、socket中TCP的四次握手釋放連接詳解

上面介紹了socket中TCP的三次握手建立過程杨帽,及其涉及的socket函數(shù)。現(xiàn)在我們介紹socket中的四次握手釋放連接的過程嗤军,:

某個應(yīng)用進程首先調(diào)用close主動關(guān)閉連接注盈,這時TCP發(fā)送一個FIN M;
另一端接收到FIN M之后叙赚,執(zhí)行被動關(guān)閉老客,對這個FIN進行確認。它的接收也作為文件結(jié)束符傳遞給應(yīng)用進程震叮,因為FIN的接收意味著應(yīng)用進程在相應(yīng)的連接上再也接收不到額外數(shù)據(jù)胧砰;
一段時間之后,接收到文件結(jié)束符的應(yīng)用進程調(diào)用close關(guān)閉它的socket苇瓣。這導(dǎo)致它的TCP也發(fā)送一個FIN N尉间;
接收到這個FIN的源發(fā)送端TCP對它進行確認。

這樣每個方向上都有一個FIN和ACK击罪。

fgets()

char *fgets(char *buf, int bufsize, FILE *stream);

*buf: 字符型指針哲嘲,指向用來存儲所得數(shù)據(jù)的地址。
bufsize: 整型數(shù)據(jù)媳禁,指明存儲數(shù)據(jù)的大小眠副。
*stream: 文件結(jié)構(gòu)體指針,將要讀取的文件流竣稽。

fgets函數(shù)用來從文件中讀入字符串囱怕。fgets函數(shù)的調(diào)用形式如下:fgets(str霍弹,n,fp)光涂;此處庞萍,fp是文件指針;str是存放在字符串的起始地址忘闻;n是一個int類型變量钝计。函數(shù)的功能是從fp所指文件中讀入n-1個字符放入str為起始地址的空間內(nèi);如果在未讀滿n-1個字符之時齐佳,已讀到一個換行符或一個EOF(文件結(jié)束標志)私恬,則結(jié)束本次讀操作,讀入的字符串中最后包含讀到的換行符炼吴。因此本鸣,確切地說,調(diào)用fgets函數(shù)時硅蹦,最多只能讀入n-1個字符荣德。讀入結(jié)束后,系統(tǒng)將自動在最后加'\0'童芹,并以str作為函數(shù)值返回涮瞻。

send()

send()是一個計算機函數(shù),功能是向一個已經(jīng)連接的socket發(fā)送數(shù)據(jù)假褪,如果無錯誤署咽,返回值為所發(fā)送數(shù)據(jù)的總數(shù),否則返回SOCKET_ERROR生音。

向一個已連接的套接口發(fā)送數(shù)據(jù)宁否。

include <winsock.h>

int PASCAL FAR send( SOCKET s, const char FAR* buf, int len, int flags);

  • s:一個用于標識已連接套接口的描述字。
  • buf:包含待發(fā)送數(shù)據(jù)的緩沖區(qū)缀遍。
  • len:緩沖區(qū)中數(shù)據(jù)的長度慕匠。
  • flags:調(diào)用執(zhí)行方式。
    linux下函數(shù)

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末域醇,一起剝皮案震驚了整個濱河市絮重,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌歹苦,老刑警劉巖青伤,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異殴瘦,居然都是意外死亡狠角,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門蚪腋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丰歌,“玉大人姨蟋,你說我怎么就攤上這事×⑻” “怎么了眼溶?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長晓勇。 經(jīng)常有香客問我堂飞,道長,這世上最難降的妖魔是什么绑咱? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任绰筛,我火速辦了婚禮,結(jié)果婚禮上描融,老公的妹妹穿的比我還像新娘铝噩。我一直安慰自己,他們只是感情好窿克,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布骏庸。 她就那樣靜靜地躺著,像睡著了一般年叮。 火紅的嫁衣襯著肌膚如雪敞恋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天谋右,我揣著相機與錄音,去河邊找鬼补箍。 笑死改执,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的坑雅。 我是一名探鬼主播辈挂,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼裹粤!你這毒婦竟也來了终蒂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤遥诉,失蹤者是張志新(化名)和其女友劉穎拇泣,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體矮锈,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡霉翔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了苞笨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片债朵。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡子眶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出序芦,到底是詐尸還是另有隱情臭杰,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布谚中,位于F島的核電站渴杆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏藏杖。R本人自食惡果不足惜将塑,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蝌麸。 院中可真熱鬧点寥,春花似錦、人聲如沸来吩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽弟疆。三九已至戚长,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間怠苔,已是汗流浹背同廉。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留柑司,地道東北人迫肖。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像攒驰,于是被迫代替她去往敵國和親蟆湖。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345