iOS socket網(wǎng)絡(luò)編程

代碼下載

服務(wù)端代碼下載地址
客戶(hù)端代碼下載地址

相關(guān)概念

  • socket是一個(gè)針對(duì)TCP和UDP編程的接口幔睬,你可以借助它建立TCP連接等。socket是對(duì)TCP/IP協(xié)議的封裝摇天,Socket本身并不是協(xié)議,而是一個(gè)調(diào)用接口(API),通過(guò)Socket,我們才能使用TCP/IP協(xié)議矿辽。Socket的出現(xiàn)只是使得程序員更方便地使用TCP/IP協(xié)議棧而已,是對(duì)TCP/IP協(xié)議的抽象郭厌,從而形成了我們知道的一些最基本的函數(shù)接口袋倔。

  • socket連接:socket連接就是所謂的長(zhǎng)連接,理論上客戶(hù)端和服務(wù)器端一旦建立起連接將不會(huì)主動(dòng)斷掉沪曙;但是由于各種環(huán)境因素可能會(huì)是連接斷開(kāi)奕污,比如說(shuō):服務(wù)器端或客戶(hù)端主機(jī)down了萎羔,網(wǎng)絡(luò)故障液走,或者兩者之間長(zhǎng)時(shí)間沒(méi)有數(shù)據(jù)傳輸,網(wǎng)絡(luò)防火墻可能會(huì)斷開(kāi)該連接以釋放網(wǎng)絡(luò)資源贾陷。所以當(dāng)一個(gè)socket連接中沒(méi)有數(shù)據(jù)的傳輸缘眶,那么為了維持連接需要發(fā)送心跳消息~~具體心跳消息格式是開(kāi)發(fā)者自己定義的。

  • TCP連接的三次握手:
    第一次握手:客戶(hù)端發(fā)送syn包(syn=j)到服務(wù)器髓废,并進(jìn)入SYN_SEND狀態(tài)巷懈,等待服務(wù)器確認(rèn);
    第二次握手:服務(wù)器收到syn包慌洪,必須確認(rèn)客戶(hù)的SYN(ack=j+1)顶燕,同時(shí)自己也發(fā)送一個(gè)SYN包(syn=k),即SYN+ACK包冈爹,此時(shí)服務(wù)器進(jìn)入SYN_RECV狀態(tài)涌攻;
    第三次握手:客戶(hù)端收到服務(wù)器的SYN+ACK包,向服務(wù)器發(fā)送確認(rèn)包ACK(ack=k+1)频伤,此包發(fā)送完畢恳谎,客戶(hù)端和服務(wù)器進(jìn)入ESTABLISHED狀態(tài),完成三次握手憋肖。

    握手過(guò)程中傳送的包里不包含數(shù)據(jù)因痛,三次握手完畢后,客戶(hù)端與服務(wù)器才正式開(kāi)始傳送數(shù)據(jù)岸更。理想狀態(tài)下鸵膏,TCP連接一旦建立,在通信雙方中的任何一方主動(dòng)關(guān)閉連接之前怎炊,TCP 連接都將被一直保持下去谭企。斷開(kāi)連接時(shí)服務(wù)器和客戶(hù)端均可以主動(dòng)發(fā)起斷開(kāi)TCP連接的請(qǐng)求用僧,斷開(kāi)過(guò)程需要經(jīng)過(guò)“四次握手”。

  • socket建立網(wǎng)絡(luò)連接的步驟
    建立Socket連接至少需要一對(duì)套接字赞咙,其中一個(gè)運(yùn)行于客戶(hù)端责循,稱(chēng)為ClientSocket ,另一個(gè)運(yùn)行于服務(wù)器端攀操,稱(chēng)為ServerSocket 院仿。
    套接字之間的連接過(guò)程分為三個(gè)步驟:服務(wù)器監(jiān)聽(tīng),客戶(hù)端請(qǐng)求速和,連接確認(rèn)歹垫。
    1。服務(wù)器監(jiān)聽(tīng):服務(wù)器端套接字并不定位具體的客戶(hù)端套接字颠放,而是處于等待連接的狀態(tài)排惨,實(shí)時(shí)監(jiān)控網(wǎng)絡(luò)狀態(tài),等待客戶(hù)端的連接請(qǐng)求碰凶。
    2暮芭。客戶(hù)端請(qǐng)求:指客戶(hù)端的套接字提出連接請(qǐng)求欲低,要連接的目標(biāo)是服務(wù)器端的套接字辕宏。為此,客戶(hù)端的套接字必須首先描述它要連接的服務(wù)器的套接字砾莱,指出服務(wù)器端套接字的地址和端口號(hào)瑞筐,然后就向服務(wù)器端套接字提出連接請(qǐng)求。
    3腊瑟。連接確認(rèn):當(dāng)服務(wù)器端套接字監(jiān)聽(tīng)到或者說(shuō)接收到客戶(hù)端套接字的連接請(qǐng)求時(shí)聚假,就響應(yīng)客戶(hù)端套接字的請(qǐng)求,建立一個(gè)新的線(xiàn)程闰非,把服務(wù)器端套接字的描述發(fā)給客戶(hù)端膘格,一旦客戶(hù)端確認(rèn)了此描述,雙方就正式建立連接河胎。而服務(wù)器端套接字繼續(xù)處于監(jiān)聽(tīng)狀態(tài)闯袒,繼續(xù)接收其他客戶(hù)端套接字的連接請(qǐng)求。

BSD socket

BSD socket:完全由c語(yǔ)言實(shí)現(xiàn)游岳,并且可以在Objective-C代碼中使用政敢。
優(yōu)點(diǎn):不同平臺(tái)中易于移植
缺點(diǎn):
無(wú)法訪(fǎng)問(wèn)操作系統(tǒng)內(nèi)建的網(wǎng)絡(luò)特性(比如系統(tǒng)范圍的VPN)。
更糟糕的是初始化socket連接并不會(huì)自動(dòng)打開(kāi)設(shè)備的Wi-Fi或是蜂窩網(wǎng)絡(luò)胚迫,無(wú)線(xiàn)網(wǎng)絡(luò)會(huì)智能的關(guān)閉以節(jié)省電池電量喷户,任何通信連接都會(huì)失敗,除非其他網(wǎng)絡(luò)進(jìn)程激活了無(wú)線(xiàn)網(wǎng)访锻。

CFNetwork對(duì)BSD Socket的分裝可以激活設(shè)備的無(wú)線(xiàn)網(wǎng)褪尝,所以幾乎所有場(chǎng)景都建議使用CFNetwork而不是BSD Socket.

最常用的API:
1.int socket(int, int, int):創(chuàng)建并初始化新的socket闹获,如果成功放回一個(gè)文件描述符,如果失敗返回0河哑。
2.int bind(int, const struct sockaddr *, socklen_t):為指定的地址與端口號(hào)分配socket避诽。
3.int listen(int, int) __DARWIN_ALIAS(listen):用于服務(wù)端監(jiān)聽(tīng)客戶(hù)端
4.int accept(int, struct sockaddr * __restrict, socklen_t * __restrict):接受連接請(qǐng)求,將客戶(hù)端地址存儲(chǔ)到clientAddress中璃谨。
5.int connect(int, const struct sockaddr *, socklen_t):連接到指定的服務(wù)器沙庐。
6.ssize_t send(int, const void *, size_t, int):在socket上最多發(fā)送XX數(shù)據(jù)。
7.ssize_t recv(int, void *, size_t, int):在socket上最多讀取XX數(shù)據(jù)佳吞。
……

服務(wù)端邏輯:如果接收到客戶(hù)端發(fā)送過(guò)來(lái)"1"拱雏,那么回復(fù)"你猜!"底扳;客戶(hù)端發(fā)送過(guò)來(lái)"2"铸抑,那么回復(fù)"謝謝!"衷模;客戶(hù)端發(fā)送過(guò)來(lái)"3"鹊汛,那么回復(fù)"對(duì)不起!"算芯;客戶(hù)端發(fā)送過(guò)來(lái)"4"柒昏,那么回復(fù)"好的!"熙揍;客戶(hù)端發(fā)送過(guò)來(lái)其他的內(nèi)容,那么一半概率原樣回復(fù)氏涩,一半概率回復(fù)"不知道你在說(shuō)什么届囚!"。


屏幕快照 2017-03-16 下午2.16.02.png

創(chuàng)建服務(wù)端:
1.創(chuàng)建socket

    struct sockaddr_in server_addr;
    server_addr.sin_len = sizeof(struct sockaddr_in);
    server_addr.sin_family = AF_INET;//AF_INET互聯(lián)網(wǎng)地址簇
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = inet_addr(address);
    bzero(&server_addr.sin_zero, 8);
    
    //創(chuàng)建socket
    int server_socket = socket(AF_INET, SOCK_STREAM, 0);//SOCK_STREAM 有鏈接
    
    if (server_socket == -1) {
        perror("socket error!");
        
        return 1;
    }

2.綁定socket:將創(chuàng)建的socket綁定到本地的IP地址和端口是尖,此socket是半相關(guān)的意系,只是負(fù)責(zé)偵聽(tīng)客戶(hù)端的連接請(qǐng)求,并不能用于和客戶(hù)端通信

    int bind_result = bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));
    if (bind_result == -1) {
        perror("bind error!");
        
        return 1;
    }

3.listen偵聽(tīng)

   if (listen(server_socket, 5)) {
        perror("listen error!");
        
        return 1;
    }

4.接受客戶(hù)端連接

    int client_socket;
    socklen_t address_len;
    struct sockaddr_in client_address;
    for (; ; ) {
        address_len = sizeof(client_address);
        client_socket = accept(server_socket, (struct sockaddr*)&client_address, &address_len);
        //1.使用多線(xiàn)程
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            //這個(gè)函數(shù)進(jìn)行數(shù)據(jù)操作
            str_echo(client_socket);
        });
    }

5.接收和發(fā)送數(shù)據(jù)

    char buf[1024];
    
    while (1) {
        bzero(buf, 1024);
        long byte_num = recv(socket, buf, 1024, 0);
        if (byte_num < 0) {
            return;
        }
        buf[byte_num] = '\0';
        printf("client said:%s\n", buf);
        
        char *result;
        NSString *str = [NSString stringWithCString:buf encoding:NSUTF8StringEncoding];
        if ([str isEqualToString:@"1"]) {
            result = "你猜饺汹!";
        }
        else if ([str isEqualToString:@"2"])
        {
            result = "謝謝蛔添!";
        }
        else if ([str isEqualToString:@"3"])
        {
            result = "對(duì)不起!";
        }
        else if ([str isEqualToString:@"4"])
        {
            result = "好的兜辞!";
        }
        else
        {
            if (arc4random()%2 == 0) {
                result = "不知道你在說(shuō)什么迎瞧!";
            }
            else
            {
                result = buf;
            }
        }
        
        send(socket, result, 1024, 0);
    }

創(chuàng)建客戶(hù)端:

    struct sockaddr_in server_addr;
    server_addr.sin_len = sizeof(struct sockaddr_in);
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(11332);
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    bzero(&(server_addr.sin_zero), 8);
    
    int server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket == -1) {
        perror("socket error");
        
        return 1;
    }
    
    char receive_msg[1024];
    char reply_msg[1024];
    
    if (connect(server_socket, (struct sockaddr*)&server_addr, sizeof(struct sockaddr_in)) == 0) {
        //connect 成功之后逸吵,其實(shí)系統(tǒng)將你創(chuàng)建的socket綁定到一個(gè)系統(tǒng)分配的端口上凶硅,且其為全相關(guān),包含服務(wù)器端的信息扫皱,可以用來(lái)和服務(wù)器端進(jìn)行通信足绅。
        
        while (1) {
            bzero(reply_msg, 1024);
            printf("replay:");
            scanf("%s", reply_msg);
            if (send(server_socket, reply_msg, 1024, 0) == -1) {
                perror("send error!");
                
                return 1;
            }
            
            bzero(receive_msg, 1024);
            long byte_num = recv(server_socket, receive_msg, 1024, 0);
            receive_msg[byte_num] = '\0';
            printf("server said:%s\n", receive_msg);
        }
    }
    
    return 0;

NSStream 讀寫(xiě)文件

Cocoa Streams包含三個(gè)相關(guān)的類(lèi): NSStream捷绑、NSInputStream 和NSOutputStream。

NSStream:是個(gè)抽象類(lèi)氢妈,定義了一些基本屬性和方法粹污;
NSInputStream:是NSStream的子類(lèi),可通過(guò)它從NSData首量、File和socket中讀取數(shù)據(jù)流厕怜;
NSOutputStream:也是NSStream的子類(lèi),可通過(guò)它將數(shù)據(jù)流寫(xiě)入NSData蕾总、File和socket粥航。

還可以給stream對(duì)象設(shè)置Delegate(NSStreamDelegate),如果沒(méi)有精確了給stream指定Delegate生百,那么默認(rèn)將Delegate設(shè)置為其自己递雀。

NSStreamDelegate只有一個(gè)方法
: - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode

NSStreamEventNone :改默認(rèn)值不代表任何事件
NSStreamEventOpenCompleted :socket被成功打開(kāi)
NSStreamEventHasBytesAvailable :有可以讀取的字節(jié)
NSStreamEventHasSpaceAvailable :緩存中可以寫(xiě)入字節(jié)
NSStreamEventErrorOccurred :操作出現(xiàn)錯(cuò)誤CFReadStreamCopyError()和CFWriteStreamCopyError()會(huì)提供更多錯(cuò)誤細(xì)節(jié)
NSStreamEventEndEncountered :socket達(dá)到字節(jié)流的末尾

通過(guò)NSStream對(duì)象讀數(shù)據(jù),可以分為如下步驟完成:
a) 從數(shù)據(jù)源創(chuàng)建和初始化一個(gè)NSStream對(duì)象蚀浆;
b) 配置run loop缀程,并打開(kāi)stream對(duì)象;
c) 響應(yīng)NSInputStream事件(NSStreamDelegate)市俊;
d) 關(guān)閉NSInputStream對(duì)象杨凑。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSString *documentStr = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    NSString *dataPath = [documentStr stringByAppendingPathComponent:@"data.txt"];
    
    NSFileManager *manager = [NSFileManager defaultManager];
    if ([manager fileExistsAtPath:dataPath]) {
        self.read = YES;
        NSLog(@"string:%@", [NSString stringWithContentsOfFile:dataPath encoding:NSUTF8StringEncoding error:nil]);
        
        NSInputStream *inStream = [[NSInputStream alloc] initWithFileAtPath:dataPath];
        [inStream setDelegate:self];
        [inStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [inStream open];
    }
    else
    {
        if ([manager createFileAtPath:dataPath contents:nil attributes:nil]) {
            self.read = NO;
            NSOutputStream *outStream = [[NSOutputStream alloc] initToFileAtPath:dataPath append:YES];
            [outStream setDelegate:self];
            [outStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [outStream open];
        }
        else
        {
            NSLog(@"文件創(chuàng)建失敗摆昧!");
        }
    }
}

#pragma mark - <NSStreamDelegate>代理方法
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
    if (self.read) {
        NSInputStream *inStream = (NSInputStream *)aStream;
        switch (eventCode) {
            case NSStreamEventHasBytesAvailable:
            {
                uint8_t data[1024];
                [inStream read:data maxLength:1024];
                printf("%s", data);
                [inStream close];
                [inStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
                inStream = nil;
            }
                break;
            case NSStreamEventEndEncountered:
            {
                [inStream close];
                [inStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
                inStream = nil;
            }
                break;
                
            default:
                break;
        }
    }
    else{
        NSOutputStream *outStream = (NSOutputStream *)aStream;
        switch (eventCode) {
            case NSStreamEventHasSpaceAvailable:
            {
                uint8_t data[] = "{name:'張三', age:10}";
                [outStream write:data maxLength:strlen((char *)data)];
                [outStream close];
                [outStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
                outStream = nil;
            }
                break;
            case NSStreamEventEndEncountered:
            {
                [outStream close];
                [outStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
                outStream = nil;
            }
                break;
                
            default:
                break;
        }
    }
}

NSStream Socket

NSStream類(lèi)不支持在IOS平臺(tái)上創(chuàng)建socket連接撩满,而CFStream支持在IOS平臺(tái)的socket行為。所以若知道遠(yuǎn)程主機(jī)的DNS或者是IP地址绅你,可以使用CFStreamCreatePairWithSocketToHost函數(shù)來(lái)創(chuàng)建socket連接伺帘,通過(guò)該函數(shù)創(chuàng)建了CFStream類(lèi)型為全雙工的socket連接,接著可以利用toll-free bridge忌锯,將CFStream對(duì)象轉(zhuǎn)換為NSStream對(duì)象伪嫁。

通過(guò)NSStream對(duì)象進(jìn)行Socket通信,與通過(guò)NSStream進(jìn)行IO操作的步驟基本一樣:
a) 創(chuàng)建NSStream對(duì)象偶垮,通過(guò)CFStreamCreatePairWithSocketToHost函數(shù)創(chuàng)建CFReadStreamRef 和CFWriteStreamRef 對(duì)象张咳;繼而將兩者轉(zhuǎn)換為NSInputStream 和NSOutputStream 對(duì)象;
b) 配置run loop似舵,并打開(kāi)NSInputStream 和NSOutputStream對(duì)象脚猾;
c) 響應(yīng)事件,在Delegate中響應(yīng)不同的信號(hào)啄枕;
d) 關(guān)閉NSStream對(duì)象婚陪。

服務(wù)端:服務(wù)端依然使用上面例子的服務(wù)端
客戶(hù)端的實(shí)現(xiàn):點(diǎn)擊1~5這五個(gè)按鈕,分別從服務(wù)端返回不同的數(shù)據(jù)频祝,進(jìn)而展示出來(lái)泌参。


屏幕快照 2017-03-16 下午3.55.49.png

由于實(shí)現(xiàn)相對(duì)簡(jiǎn)單脆淹,就不加闡述說(shuō)明了,實(shí)現(xiàn)代碼如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self startSocket:@"127.0.0.1" andPort:11332];
}

- (void)startSocket:(NSString *)address andPort:(int)port
{
    CFReadStreamRef readRef;
    CFWriteStreamRef writeRef;
    
    CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)address, port, &readRef, &writeRef);
    
    NSInputStream *inputStream = (__bridge NSInputStream *)readRef;
    NSOutputStream *outputStream = (__bridge NSOutputStream *)writeRef;
    
    inputStream.delegate = self;
    outputStream.delegate = self;
    
    [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    
    [inputStream open];
    [outputStream open];
    
    self.outputStream = outputStream;
}

- (IBAction)sendMsg:(UIButton *)sender {
    if (sender.currentTitle > 0) {
        const char *output = sender.currentTitle.UTF8String;
        [self.outputStream write:(const uint8_t *)output maxLength:strlen(output)];
    }
}

- (void)showMessage:(NSString *)msg
{
    if (!self.msgLabel) {
        UIFont *font = [UIFont systemFontOfSize:14];
        UIColor *color = [UIColor blackColor];
        UIColor *backColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.2];
        
        UILabel *label = [[UILabel alloc] init];
        label.textColor = color;
        label.font = font;
        label.textAlignment = NSTextAlignmentCenter;
        label.backgroundColor = backColor;
        self.msgLabel = label;
    }
    
    CGFloat screenW = [UIScreen mainScreen].bounds.size.width;
    CGFloat screenH = [UIScreen mainScreen].bounds.size.height;
    CGFloat W = screenW - 16;
    CGSize size = [msg boundingRectWithSize:CGSizeMake(W, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:self.msgLabel.font} context:nil].size;
    W = size.width;
    CGFloat H = size.height;
    CGFloat X = (screenW - W)/2;
    CGFloat Y = (screenH - H)/2;
    
    self.msgLabel.frame = CGRectMake(X, Y, W, H);
    self.msgLabel.text = msg;
    [self.view addSubview:self.msgLabel];
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.msgLabel removeFromSuperview];
    });
}

#pragma mark - <NSStreamDelegate>代理方法
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
    switch (eventCode) {
        case NSStreamEventNone:
            break;
        case NSStreamEventOpenCompleted:
            break;
        case NSStreamEventHasBytesAvailable:
        {
            uint8_t buf[1024];
            NSInteger len = 0;
            NSInputStream *inputStream = (NSInputStream *)aStream;
            len = [inputStream read:buf maxLength:1024];
            if (len) {
                [self showMessage:[NSString stringWithCString:(const char *)buf encoding:NSUTF8StringEncoding]];
            }
            break;
        }
        case NSStreamEventHasSpaceAvailable:
            break;
        case NSStreamEventErrorOccurred:
        {
            [aStream close];
            break;
        }
        case NSStreamEventEndEncountered:
        {
            [aStream close];
            [aStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            aStream = nil;
            break;
        }
            
        default:
            break;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末沽一,一起剝皮案震驚了整個(gè)濱河市盖溺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌铣缠,老刑警劉巖烘嘱,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蝗蛙,居然都是意外死亡蝇庭,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)捡硅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)哮内,“玉大人,你說(shuō)我怎么就攤上這事壮韭”狈ⅲ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵喷屋,是天一觀的道長(zhǎng)琳拨。 經(jīng)常有香客問(wèn)我,道長(zhǎng)屯曹,這世上最難降的妖魔是什么狱庇? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮是牢,結(jié)果婚禮上僵井,老公的妹妹穿的比我還像新娘。我一直安慰自己驳棱,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布农曲。 她就那樣靜靜地躺著社搅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪乳规。 梳的紋絲不亂的頭發(fā)上形葬,一...
    開(kāi)封第一講書(shū)人閱讀 51,590評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音暮的,去河邊找鬼笙以。 笑死,一個(gè)胖子當(dāng)著我的面吹牛冻辩,可吹牛的內(nèi)容都是我干的猖腕。 我是一名探鬼主播拆祈,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼倘感!你這毒婦竟也來(lái)了放坏?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤老玛,失蹤者是張志新(化名)和其女友劉穎淤年,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蜡豹,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡麸粮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了镜廉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弄诲。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖桨吊,靈堂內(nèi)的尸體忽然破棺而出威根,到底是詐尸還是另有隱情,我是刑警寧澤视乐,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布洛搀,位于F島的核電站,受9級(jí)特大地震影響佑淀,放射性物質(zhì)發(fā)生泄漏留美。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一伸刃、第九天 我趴在偏房一處隱蔽的房頂上張望谎砾。 院中可真熱鬧,春花似錦捧颅、人聲如沸景图。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)挚币。三九已至,卻和暖如春扣典,著一層夾襖步出監(jiān)牢的瞬間妆毕,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工贮尖, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留笛粘,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像薪前,于是被迫代替她去往敵國(guó)和親润努。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

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