進(jìn)程間通信之管道

前言

管道是UNIX環(huán)境中歷史最悠久的進(jìn)程間通信方式津畸,也是最簡(jiǎn)單的進(jìn)程間通信方式羞福,一般用來(lái)作為IPC的入門(mén),最合適不過(guò)了续膳。

本文主要說(shuō)明在Linux環(huán)境上如何使用管道。閱讀本文可以幫你解決以下問(wèn)題:

  • 什么是管道和為什么要有管道收班?
  • 管道怎么分類(lèi)?(匿名管道和命名管道)
  • 管道的實(shí)現(xiàn)是什么樣的谒兄?
  • 管道有多大摔桦?
  • 管道的大小是不是可以調(diào)整?如何調(diào)整承疲?(cat /proc/sys/file/pipe-max-size)

在Linux 2.6.11之前邻耕,PIPESIZE和PIPEBUF實(shí)際上是一樣的。在這之后燕鸽,Linux重新實(shí)現(xiàn)了一個(gè)管道緩存兄世,并將它與寫(xiě)操作的PIPEBUF實(shí)現(xiàn)成了不同的概念,形成了一個(gè)默認(rèn)長(zhǎng)度為65536字節(jié)的PIPESIZE啊研,而PIPEBUF只影響相關(guān)讀寫(xiě)操作的原子性御滩。從Linux 2.6.35之后鸥拧,在fcntl系統(tǒng)調(diào)用方法中實(shí)現(xiàn)了F_GETPIPE_SZ和F_SETPIPE_SZ操作,來(lái)分別查看當(dāng)前管道容量和設(shè)置管道容量削解。管道容量容量上限可以在/proc/sys/fs/pipe-max-size進(jìn)行設(shè)置富弦。

核心知識(shí)點(diǎn)

1、管道是一種半雙工的進(jìn)程間通訊IPC方式氛驮。

2腕柜、一個(gè)簡(jiǎn)單的例子是在使用shell命令行時(shí)使用的“l(fā)s -l /etc | wc -l”,“ps -ef|grep mysql”等矫废。

3盏缤、管道本質(zhì)上就是一個(gè)文件,前面的進(jìn)程以寫(xiě)方式打開(kāi)文件蓖扑,后面的進(jìn)程以讀方式打開(kāi)蛾找。

4、雖然實(shí)現(xiàn)形態(tài)上是文件赵誓,但是管道本身并不占用磁盤(pán)或者其他外部存儲(chǔ)的空間打毛。在Linux的實(shí)現(xiàn)上,它占用的是內(nèi)存空間俩功。所以幻枉,Linux上的管道就是一個(gè)操作方式為文件的內(nèi)存緩沖區(qū)。

管道的含義

管道诡蜓,英文為pipe熬甫。這是一個(gè)我們?cè)趯W(xué)習(xí)Linux命令行的時(shí)候就會(huì)引入的一個(gè)很重要的概念。它的發(fā)明人是道格拉斯.麥克羅伊蔓罚,這位也是UNIX上早期shell的發(fā)明人椿肩。他在發(fā)明了shell之后,發(fā)現(xiàn)系統(tǒng)操作執(zhí)行命令的時(shí)候豺谈,經(jīng)常有需求要將一個(gè)程序的輸出交給另一個(gè)程序進(jìn)行處理郑象,這種操作可以使用輸入輸出重定向加文件搞定,比如:

[GeekerLou@Linux pipe]$ ls  -l /etc/ > etc.txt
[GeekerLou@Linux pipe]$ wc -l etc.txt
183 etc.txt

但是這樣未免顯得太麻煩了茬末。所以厂榛,管道的概念應(yīng)運(yùn)而生。目前在任何一個(gè)shell中丽惭,都可以使用“|”連接兩個(gè)命令击奶,shell會(huì)將前后兩個(gè)進(jìn)程的輸入輸出用一個(gè)管道相連,以便達(dá)到進(jìn)程間通信的目的:

[GeekerLou@Linux pipe]$ ls -l /etc/ | wc -l
183

對(duì)比以上兩種方法责掏,我們也可以理解為柜砾,管道本質(zhì)上就是一個(gè)文件,前面的進(jìn)程以寫(xiě)方式打開(kāi)文件换衬,后面的進(jìn)程以讀方式打開(kāi)痰驱。這樣前面寫(xiě)完后面讀证芭,于是就實(shí)現(xiàn)了通信。實(shí)際上管道的設(shè)計(jì)也是遵循UNIX的“一切皆文件”設(shè)計(jì)原則的萄唇,它本質(zhì)上就是一個(gè)文件檩帐。Linux系統(tǒng)直接把管道實(shí)現(xiàn)成了一種文件系統(tǒng),借助VFS給應(yīng)用程序提供操作接口另萤。

雖然實(shí)現(xiàn)形態(tài)上是文件湃密,但是管道本身并不占用磁盤(pán)或者其他外部存儲(chǔ)的空間。在Linux的實(shí)現(xiàn)上四敞,它占用的是內(nèi)存空間泛源。所以,Linux上的管道就是一個(gè)操作方式為文件的內(nèi)存緩沖區(qū)忿危。

管道的分類(lèi)和使用

Linux上的管道分兩種類(lèi)型:

  1. 匿名管道
  2. 命名管道

這兩種管道也叫做有名或無(wú)名管道达箍。匿名管道最常見(jiàn)的形態(tài)就是我們?cè)趕hell操作中最常用的”|”。它的特點(diǎn)是只能在父子進(jìn)程中使用铺厨,父進(jìn)程在產(chǎn)生子進(jìn)程前必須打開(kāi)一個(gè)管道文件缎玫,然后fork產(chǎn)生子進(jìn)程,這樣子進(jìn)程通過(guò)拷貝父進(jìn)程的進(jìn)程地址空間獲得同一個(gè)管道文件的描述符解滓,以達(dá)到使用同一個(gè)管道通信的目的赃磨。此時(shí)除了父子進(jìn)程外,沒(méi)人知道這個(gè)管道文件的描述符洼裤,所以通過(guò)這個(gè)管道中的信息無(wú)法傳遞給其他進(jìn)程邻辉。這保證了傳輸數(shù)據(jù)的安全性,當(dāng)然也降低了管道了通用性腮鞍,于是系統(tǒng)還提供了命名管道值骇。

我們可以使用mkfifo或mknod命令來(lái)創(chuàng)建一個(gè)命名管道,這跟創(chuàng)建一個(gè)文件沒(méi)有什么區(qū)別:

[GeekerLou@Linux pipe]$ mkfifo pipe
[GeekerLou@Linux pipe]$ ls -l pipe
prw-r–r– 1 GeekerLou GeekerLou 0 Jul 15 21:24 pipe

可以看到創(chuàng)建出來(lái)的文件類(lèi)型比較特殊移国,是p類(lèi)型吱瘩。表示這是一個(gè)管道文件。有了這個(gè)管道文件桥狡,系統(tǒng)中就有了對(duì)一個(gè)管道的全局名稱(chēng)搅裙,于是任何兩個(gè)不相關(guān)的進(jìn)程都可以通過(guò)這個(gè)管道文件進(jìn)行通信了。比如我們現(xiàn)在讓一個(gè)進(jìn)程寫(xiě)這個(gè)管道文件:

[GeekerLou@Linux pipe]$ echo ############ > pipe

此時(shí)這個(gè)寫(xiě)操作會(huì)阻塞裹芝,因?yàn)楣艿懒硪欢藳](méi)有人讀。這是內(nèi)核對(duì)管道文件定義的默認(rèn)行為娜汁。此時(shí)如果有進(jìn)程讀這個(gè)管道嫂易,那么這個(gè)寫(xiě)操作的阻塞才會(huì)解除:

[GeekerLou@Linux pipe]$ cat pipe
############

大家可以觀察到,當(dāng)我們cat完這個(gè)文件之后掐禁,另一端的echo命令也返回了怜械。這就是命名管道颅和。

Linux系統(tǒng)無(wú)論對(duì)于命名管道和匿名管道,底層都用的是同一種文件系統(tǒng)的操作行為缕允,這種文件系統(tǒng)叫pipefs峡扩。大家可以在/etc/proc/filesystems文件中找到你的系統(tǒng)是不是支持這種文件系統(tǒng):

[GeekerLou@Linux pipe]$ cat /proc/filesystems | grep pipefs
nodev   pipefs

觀察完了如何在命令行中使用管道之后,我們?cè)賮?lái)看看如何在系統(tǒng)編程中使用管道障本。

PIPE

我們可以把匿名管道和命名管道分別叫做PIPE和FIFO教届。這主要因?yàn)樵谙到y(tǒng)編程中,創(chuàng)建匿名管道的系統(tǒng)調(diào)用是pipe()严卖,而創(chuàng)建命名管道的函數(shù)是mkfifo()站超。使用mknod()系統(tǒng)調(diào)用并指定文件類(lèi)型為為S_IFIFO也可以創(chuàng)建一個(gè)FIFO旺上。

使用pipe()系統(tǒng)調(diào)用可以創(chuàng)建一個(gè)匿名管道,這個(gè)系統(tǒng)調(diào)用的原型為:

#include <unistd.h>
int pipe(int pipefd[2]);

這個(gè)方法將會(huì)創(chuàng)建出兩個(gè)文件描述符强霎,可以使用pipefd這個(gè)數(shù)組來(lái)引用這兩個(gè)描述符進(jìn)行文件操作。pipefd[0]是讀方式打開(kāi)蓉冈,作為管道的讀描述符城舞。pipefd[1]是寫(xiě)方式打開(kāi),作為管道的寫(xiě)描述符寞酿。從管道寫(xiě)端寫(xiě)入的數(shù)據(jù)會(huì)被內(nèi)核緩存直到有人從另一端讀取為止家夺。我們來(lái)看一下如何在一個(gè)進(jìn)程中使用管道,雖然這個(gè)例子并沒(méi)有什么意義:

//pipe.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

#define STRING "hello world!"

int main()
{
    int pipefd[2];
    char buf[BUFSIZ];
    if (pipe(pipefd) == -1) {
        perror("pipe()");
        exit(1);
    }
    if (write(pipefd[1], STRING, strlen(STRING)) < 0) {
        perror("write()");
        exit(1);
    }
    if (read(pipefd[0], buf, BUFSIZ) < 0) {
        perror("write()");
        exit(1);
    }
    printf("%s\n", buf);
 
    exit(0);
}

這個(gè)程序創(chuàng)建了一個(gè)管道熟嫩,并且對(duì)管道寫(xiě)了一個(gè)字符串之后從管道讀取秦踪,并打印在標(biāo)準(zhǔn)輸出上。用一個(gè)圖來(lái)說(shuō)明這個(gè)程序的狀態(tài)就是這樣的:


一個(gè)進(jìn)程自己給自己發(fā)送消息這當(dāng)然不叫進(jìn)程間通信掸茅,所以實(shí)際情況中我們不會(huì)在單個(gè)進(jìn)程中使用管道椅邓。進(jìn)程在pipe創(chuàng)建完管道之后,往往都要fork產(chǎn)生子進(jìn)程昧狮,成為如下圖表示的樣子:


如圖中描述景馁,fork產(chǎn)生的子進(jìn)程會(huì)繼承父進(jìn)程對(duì)應(yīng)的文件描述符。利用這個(gè)特性逗鸣,父進(jìn)程先pipe創(chuàng)建管道之后合住,子進(jìn)程也會(huì)得到同一個(gè)管道的讀寫(xiě)文件描述符。從而實(shí)現(xiàn)了父子兩個(gè)進(jìn)程使用一個(gè)管道可以完成半雙工通信撒璧。此時(shí)透葛,父進(jìn)程可以通過(guò)fd[1]給子進(jìn)程發(fā)消息,子進(jìn)程通過(guò)fd[0]讀卿樱。子進(jìn)程也可以通過(guò)fd[1]給父進(jìn)程發(fā)消息僚害,父進(jìn)程用fd[0]讀。程序?qū)嵗缦拢?/p>

//pipe_parent_child.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>

#define STRING "hello world!"
 
int main()
{
    int pipefd[2];
    pid_t pid;
    char buf[BUFSIZ];
    if (pipe(pipefd) == -1) {
        perror("pipe()");
        exit(1);
    }
    pid = fork();
    if (pid == -1) {
        perror("fork()");
        exit(1);
    }
    if (pid == 0) {
        /* this is child. */
        printf("Child pid is: %d\n", getpid());
        if (read(pipefd[0], buf, BUFSIZ) < 0) {
            perror("write()");
            exit(1);
        }
        printf("%s\n", buf);
        bzero(buf, BUFSIZ);
        snprintf(buf, BUFSIZ, "Message from child: My pid is: %d", getpid());
        if (write(pipefd[1], buf, strlen(buf)) < 0) {
            perror("write()");
            exit(1);
        }
    } else {
        /* this is parent */
       printf("Parent pid is: %d\n", getpid());
        snprintf(buf, BUFSIZ, "Message from parent: My pid is: %d", getpid());
        if (write(pipefd[1], buf, strlen(buf)) < 0) {
            perror("write()");
            exit(1);
        }
        sleep(1);
        bzero(buf, BUFSIZ);
        if (read(pipefd[0], buf, BUFSIZ) < 0) {
            perror("write()");
            exit(1);
        }
        printf("%s\n", buf);
        wait(NULL);
    }
    exit(0);
}

父進(jìn)程先給子進(jìn)程發(fā)一個(gè)消息繁调,子進(jìn)程接收到之后打印消息萨蚕,之后再給父進(jìn)程發(fā)消息靶草,父進(jìn)程再打印從子進(jìn)程接收到的消息。程序執(zhí)行效果:

[zorro@zorro-pc pipe]$ ./pipe_parent_child
Parent pid is: 8309
Child pid is: 8310
Message from parent: My pid is: 8309
Message from child: My pid is: 8310

從這個(gè)程序中我們可以看到岳遥,管道實(shí)際上可以實(shí)現(xiàn)一個(gè)半雙工通信的機(jī)制奕翔。使用同一個(gè)管道的父子進(jìn)程可以分時(shí)給對(duì)方發(fā)送消息。我們也可以看到對(duì)管道讀寫(xiě)的一些特點(diǎn)浩蓉,即:

  1. 在管道中沒(méi)有數(shù)據(jù)的情況下派继,對(duì)管道的讀操作會(huì)阻塞,直到管道內(nèi)有數(shù)據(jù)為止妻往。
  2. 當(dāng)一次寫(xiě)的數(shù)據(jù)量不超過(guò)管道容量的時(shí)候互艾,對(duì)管道的寫(xiě)操作一般不會(huì)阻塞,直接將要寫(xiě)的數(shù)據(jù)寫(xiě)入管道緩沖區(qū)即可讯泣。

當(dāng)然寫(xiě)操作也不會(huì)再所有情況下都不阻塞纫普。這里我們要先來(lái)了解一下管道的內(nèi)核實(shí)現(xiàn)。上文說(shuō)過(guò)好渠,管道實(shí)際上就是內(nèi)核控制的一個(gè)內(nèi)存緩沖區(qū)昨稼,既然是緩沖區(qū),就有容量上限拳锚。我們把管道一次最多可以緩存的數(shù)據(jù)量大小叫做PIPESIZE假栓。內(nèi)核在處理管道數(shù)據(jù)的時(shí)候,底層也要調(diào)用類(lèi)似read和write這樣的方法進(jìn)行數(shù)據(jù)拷貝霍掺,這種內(nèi)核操作每次可以操作的數(shù)據(jù)量也是有限的匾荆,一般的操作長(zhǎng)度為一個(gè)page,即默認(rèn)為4k字節(jié)杆烁。我們把每次可以操作的數(shù)據(jù)量長(zhǎng)度叫做PIPEBUF牙丽。POSIX標(biāo)準(zhǔn)中,對(duì)PIPEBUF有長(zhǎng)度限制兔魂,要求其最小長(zhǎng)度不得低于512字節(jié)烤芦。PIPEBUF的作用是,內(nèi)核在處理管道的時(shí)候析校,如果每次讀寫(xiě)操作的數(shù)據(jù)長(zhǎng)度不大于PIPEBUF時(shí)构罗,保證其操作是原子的。而PIPESIZE的影響是智玻,大于其長(zhǎng)度的寫(xiě)操作會(huì)被阻塞遂唧,直到當(dāng)前管道中的數(shù)據(jù)被讀取為止。

在Linux 2.6.11之前吊奢,PIPESIZE和PIPEBUF實(shí)際上是一樣的蠢箩。在這之后,Linux重新實(shí)現(xiàn)了一個(gè)管道緩存事甜,并將它與寫(xiě)操作的PIPEBUF實(shí)現(xiàn)成了不同的概念谬泌,形成了一個(gè)默認(rèn)長(zhǎng)度為65536字節(jié)的PIPESIZE,而PIPEBUF只影響相關(guān)讀寫(xiě)操作的原子性逻谦。從Linux 2.6.35之后掌实,在fcntl系統(tǒng)調(diào)用方法中實(shí)現(xiàn)了F_GETPIPE_SZ和F_SETPIPE_SZ操作,來(lái)分別查看當(dāng)前管道容量和設(shè)置管道容量邦马。管道容量容量上限可以在/proc/sys/fs/pipe-max-size進(jìn)行設(shè)置贱鼻。

#define BUFSIZE 65536
......
ret = fcntl(pipefd[1], F_GETPIPE_SZ);
if (ret < 0) {
    perror("fcntl()");
    exit(1);
}
printf("PIPESIZE: %d\n", ret);
ret = fcntl(pipefd[1], F_SETPIPE_SZ, BUFSIZE);
if (ret < 0) {
    perror("fcntl()");
    exit(1);
}
 
......

PIPEBUF和PIPESIZE對(duì)管道操作的影響會(huì)因?yàn)楣艿烂枋龇欠癖辉O(shè)置為非阻塞方式而有行為變化,n為要寫(xiě)入的數(shù)據(jù)量時(shí)具體為:

1)O_NONBLOCK關(guān)閉滋将,n <= PIPE_BUF:

n個(gè)字節(jié)的寫(xiě)入操作是原子操作邻悬,write系統(tǒng)調(diào)用可能會(huì)因?yàn)楣艿廊萘?PIPESIZE)沒(méi)有足夠的空間存放n字節(jié)長(zhǎng)度而阻塞。

2)O_NONBLOCK打開(kāi)随闽,n <= PIPE_BUF:

如果有足夠的空間存放n字節(jié)長(zhǎng)度父丰,write調(diào)用會(huì)立即返回成功,并且對(duì)數(shù)據(jù)進(jìn)行寫(xiě)操作掘宪《晟龋空間不夠則立即報(bào)錯(cuò)返回,并且errno被設(shè)置為EAGAIN魏滚。

3)O_NONBLOCK關(guān)閉镀首,n > PIPE_BUF:

對(duì)n字節(jié)的寫(xiě)入操作不保證是原子的,就是說(shuō)這次寫(xiě)入操作的數(shù)據(jù)可能會(huì)跟其他進(jìn)程寫(xiě)這個(gè)管道的數(shù)據(jù)進(jìn)行交叉鼠次。當(dāng)管道容量長(zhǎng)度低于要寫(xiě)的數(shù)據(jù)長(zhǎng)度的時(shí)候write操作會(huì)被阻塞更哄。

4)O_NONBLOCK打開(kāi),n > PIPE_BUF:

如果管道空間已滿腥寇。write調(diào)用報(bào)錯(cuò)返回并且errno被設(shè)置為EAGAIN成翩。如果沒(méi)滿,則可能會(huì)寫(xiě)入從1到n個(gè)字節(jié)長(zhǎng)度花颗,這取決于當(dāng)前管道的剩余空間長(zhǎng)度捕传,并且這些數(shù)據(jù)可能跟別的進(jìn)程的數(shù)據(jù)有交叉。

以上是在使用半雙工管道的時(shí)候要注意的事情扩劝,因?yàn)樵谶@種情況下庸论,管道的兩端都可能有多個(gè)進(jìn)程進(jìn)行讀寫(xiě)處理。如果再加上線程棒呛,則事情可能變得更復(fù)雜聂示。實(shí)際上,我們?cè)谑褂霉艿赖臅r(shí)候簇秒,并不推薦這樣來(lái)用鱼喉。管道推薦的使用方法是其單工模式:即只有兩個(gè)進(jìn)程通信,一個(gè)進(jìn)程只寫(xiě)管道,另一個(gè)進(jìn)程只讀管道扛禽。實(shí)現(xiàn)為:(管道的經(jīng)典實(shí)現(xiàn)代碼)

//pipe_parent_child2.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#define STRING "hello world!"
int main()
{
    int pipefd[2];
    pid_t pid;
    char buf[BUFSIZ];
    if (pipe(pipefd) == -1) {
        perror("pipe()");
        exit(1);
    }
    pid = fork();
    if (pid == -1) {
        perror("fork()");
        exit(1);
    }
    if (pid == 0) {
        /* this is child. */
        close(pipefd[1]);
        printf("Child pid is: %d\n", getpid());
        if (read(pipefd[0], buf, BUFSIZ) < 0) {
            perror("write()");
            exit(1);
       }
        printf("%s\n", buf);
 
    } else {
        /* this is parent */
        close(pipefd[0]);
        printf("Parent pid is: %d\n", getpid());
        snprintf(buf, BUFSIZ, "Message from parent: My pid is: %d", getpid());
        if (write(pipefd[1], buf, strlen(buf)) < 0) {
            perror("write()");
            exit(1);
        }
        wait(NULL);
    }
    exit(0);
}

這個(gè)程序?qū)嶋H上比上一個(gè)要簡(jiǎn)單锋边,父進(jìn)程關(guān)閉管道的讀端,只寫(xiě)管道编曼。子進(jìn)程關(guān)閉管道的寫(xiě)端豆巨,只讀管道。整個(gè)管道的打開(kāi)效果最后成為下圖所示:


此時(shí)兩個(gè)進(jìn)程就只用管道實(shí)現(xiàn)了一個(gè)單工通信掐场,并且這種狀態(tài)下不用考慮多個(gè)進(jìn)程同時(shí)對(duì)管道寫(xiě)產(chǎn)生的數(shù)據(jù)交叉的問(wèn)題往扔,這是最經(jīng)典的管道打開(kāi)方式,也是我們推薦的管道使用方式熊户。另外萍膛,作為一個(gè)程序員,即使我們了解了Linux管道的實(shí)現(xiàn)嚷堡,我們的代碼也不能依賴(lài)其特性蝗罗,所以處理管道時(shí)該越界判斷還是要判斷,該錯(cuò)誤檢查還是要檢查麦到,這樣代碼才能更健壯绿饵。

FIFO

命名管道在底層的實(shí)現(xiàn)跟匿名管道完全一致,區(qū)別只是命名管道會(huì)有一個(gè)全局可見(jiàn)的文件名以供別人open打開(kāi)使用瓶颠。再程序中創(chuàng)建一個(gè)命名管道文件的方法有兩種拟赊,一種是使用mkfifo函數(shù)。另一種是使用mknod系統(tǒng)調(diào)用粹淋,例子如下:

//mymkfifo.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
 
int main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Argument error!\n");
        exit(1);
    }
/*
    if (mkfifo(argv[1], 0600) < 0) {
        perror("mkfifo()");
        exit(1);
    }
*/
    if (mknod(argv[1], 0600|S_IFIFO, 0) < 0) {
        perror("mknod()");
        exit(1);
    }
    exit(0);
}

我們使用第一個(gè)參數(shù)作為創(chuàng)建的文件路徑吸祟。創(chuàng)建完之后,其他進(jìn)程就可以使用open()桃移、read()屋匕、write()標(biāo)準(zhǔn)文件操作等方法進(jìn)行使用了。其余所有的操作跟匿名管道使用類(lèi)似借杰。需要注意的是过吻,無(wú)論命名還是匿名管道,它的文件描述都沒(méi)有偏移量的概念蔗衡,所以不能用lseek進(jìn)行偏移量調(diào)整纤虽。

關(guān)于管道的其它問(wèn)題,比如popen绞惦、pclose的使用等話題逼纸,《UNIX環(huán)境高級(jí)編程》中的相關(guān)章節(jié)已經(jīng)講的很清楚了。如果想學(xué)習(xí)補(bǔ)充這些知識(shí)济蝉,請(qǐng)參見(jiàn)此書(shū)杰刽。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末菠发,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子贺嫂,更是在濱河造成了極大的恐慌滓鸠,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涝婉,死亡現(xiàn)場(chǎng)離奇詭異哥力,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)墩弯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)寞射,“玉大人渔工,你說(shuō)我怎么就攤上這事∏盼拢” “怎么了引矩?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)侵浸。 經(jīng)常有香客問(wèn)我旺韭,道長(zhǎng),這世上最難降的妖魔是什么掏觉? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任区端,我火速辦了婚禮,結(jié)果婚禮上澳腹,老公的妹妹穿的比我還像新娘织盼。我一直安慰自己,他們只是感情好酱塔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布沥邻。 她就那樣靜靜地躺著,像睡著了一般羊娃。 火紅的嫁衣襯著肌膚如雪唐全。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天蕊玷,我揣著相機(jī)與錄音邮利,去河邊找鬼。 笑死集畅,一個(gè)胖子當(dāng)著我的面吹牛近弟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播挺智,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼祷愉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼窗宦!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起二鳄,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤赴涵,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后订讼,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體髓窜,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年欺殿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了寄纵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡脖苏,死狀恐怖程拭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情棍潘,我是刑警寧澤恃鞋,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站亦歉,受9級(jí)特大地震影響恤浪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜肴楷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一水由、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧阶祭,春花似錦绷杜、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至瑰剃,卻和暖如春齿诉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背晌姚。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工粤剧, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人挥唠。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓抵恋,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親宝磨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子弧关,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

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