TCP 看我就夠了

TCP的初識

TCP 是一種面向連接的,可靠的,基于字節(jié)流的傳輸層通信協(xié)議.TCP工作在網(wǎng)絡(luò)OSI七層模型中的第四層-傳輸層,下面一張圖展示OSI七層模型及每一層的作用和對應(yīng)的協(xié)議.


圖.png

TCP是傳輸層協(xié)議衅谷,在進(jìn)行數(shù)據(jù)傳輸之前使用三次握手協(xié)議建立連接群嗤,大體的過程是客戶端發(fā)出SYN連接請求后,服務(wù)端接收請求后應(yīng)答SYN+ACK譬重,客戶端收到服務(wù)端應(yīng)答后應(yīng)答ACK,這種建立連接的方法可以防止產(chǎn)生錯誤的連接罐氨,防止已失效的連接請求報文段突然又傳送到了服務(wù)端臀规。TCP三次握手過程圖示如下:

圖片.png

TCP三次握手過程描述如下:

1.客戶端發(fā)送SYN標(biāo)志位為1,Sequence Number為x的連接請求報文段栅隐,然后客戶端進(jìn)入SYN_SEND狀態(tài)塔嬉,等待服務(wù)器的確認(rèn)響應(yīng)玩徊;
2.服務(wù)器收到客戶端的連接請求,對這個SYN報文段進(jìn)行確認(rèn)谨究,然后發(fā)送Acknowledgment Number為x+1(Sequence Number+1)恩袱,SYN標(biāo)志位和ACK標(biāo)志位均為1,Sequence Number為y的報文段(即SYN+ACK報文段)給客戶端胶哲,此時服務(wù)器進(jìn)入SYN_RECV狀態(tài)畔塔;
3.客戶端收到服務(wù)器的SYN+ACK報文段,確認(rèn)ACK后鸯屿,發(fā)送Acknowledgment Number為y+1澈吨,SYN標(biāo)志位為0,ACK標(biāo)志位為1的報文段寄摆,發(fā)送完成后谅辣,客戶端和服務(wù)器端都進(jìn)入ESTABLISHED狀態(tài),完成TCP三次握手婶恼,客戶端和服務(wù)器端成功地建立連接桑阶,可以開始傳輸數(shù)據(jù)了。

當(dāng)數(shù)據(jù)傳送完成后熙尉,為了正確完整的完成數(shù)據(jù)傳輸联逻,需要經(jīng)過四次揮手?jǐn)嚅_連接。TCP四次揮過程圖示如下:

圖.png

TCP四次揮手過程描述如下:

1.客戶端發(fā)送Sequence Number為x+2检痰,Acknowledgment Number為y+1的FIN報文段包归,客戶端進(jìn)入FIN_WAIT_1狀態(tài),即告訴服務(wù)端沒有數(shù)據(jù)需要傳輸了铅歼,請求關(guān)閉連接公壤;
2.服務(wù)端收到客戶端的FIN報文段后,向客戶端應(yīng)答一個Acknowledgment Number為Sequence Number+1的ACK報文段椎椰,即應(yīng)答客戶端你的請求我收到了厦幅,但是我還沒準(zhǔn)備好,請等待我的關(guān)閉請求慨飘∑垦辏客戶端收到后進(jìn)入FIN_WAIT_2狀態(tài)衙四;
3.服務(wù)端完成數(shù)據(jù)傳輸后向客戶端發(fā)送Sequence Number為y+1的FIN報文段,請求關(guān)閉連接,服務(wù)器進(jìn)入LAST_ACK狀態(tài)钢悲;
4.客戶端收到服務(wù)端的FIN報文段后漠魏,向服務(wù)端應(yīng)答一個Acknowledgment Number為Sequence Number+1的ACK報文段澳厢,然后客戶端進(jìn)入TIME_WAIT狀態(tài)鸦采;服務(wù)端收到客戶端的ACK報文段后關(guān)閉連接進(jìn)入CLOSED狀態(tài),客戶端等待2MSL后依然沒有收到回復(fù)稽坤,則證明服務(wù)端已正常關(guān)閉丈甸,客戶端此時關(guān)閉連接進(jìn)入CLOSED狀態(tài)糯俗。

TCP的使用

上面的那些都是理論的知識,在我們實(shí)際應(yīng)用中不必過分鉆研(當(dāng)然除了你本來就是研究這個的或者你很感興趣),我們要做的,要學(xué)習(xí)的就是怎么在項(xiàng)目中使用它,下面我就先講一下我在項(xiàng)目中的使用以及遇到的問題.
* 我們的需求:在我們的項(xiàng)目中有一個微課模塊,我們的需求就是要做到當(dāng)老師或者管理員進(jìn)入微課的時候能夠通知到所有人,針對這個問題,我跟總監(jiān)經(jīng)過討論,決定使用TCP.(至于為什么不走IM自定義消息就不在累述)
* 我們的實(shí)現(xiàn):我們使用Socket來完成的TCP鏈接 ,服務(wù)端是用MINA2搭建,IOS 使用CocoaAsyncSocket,安卓也是用的MINA2
其實(shí)在這里有些人還搞不清楚什么的TCP 什么是UDP 什么是HTTP 什么是Socket,那我就大概說下我的理解:
# socket是對TCP/IP協(xié)議的封裝和應(yīng)用(程序員層面上)。也可以說睦擂,TPC/IP協(xié)議是傳輸層協(xié)議得湘,主要解決數(shù)據(jù) 如何在網(wǎng)絡(luò)中傳輸,HTTP是應(yīng)用層協(xié)議祈匙,主要解決如何包裝數(shù)據(jù)忽刽。socket是讓我們更簡單的使用TCP/IP協(xié)議

我們在傳輸數(shù)據(jù)時,可以只使用(傳輸層)TCP/IP協(xié)議夺欲,但是那樣的話跪帝,如 果沒有應(yīng)用層,便無法識別數(shù)據(jù)內(nèi)容些阅,如果想要使傳輸?shù)臄?shù)據(jù)有意義伞剑,則必須使用到應(yīng)用層協(xié)議,應(yīng)用層協(xié)議有很多市埋,比如HTTP黎泣、FTP、TELNET等缤谎,也 可以自己定義應(yīng)用層協(xié)議抒倚。WEB使用HTTP協(xié)議作應(yīng)用層協(xié)議,以封裝HTTP文本信息坷澡,然后使用TCP/IP做傳輸層協(xié)議將它發(fā)到網(wǎng)絡(luò)上托呕。實(shí)際上socket是對TCP/IP協(xié)議的封裝,Socket本身并不是協(xié)議频敛,而是一個調(diào)用接口(API)项郊,通過Socket,我們才能使用TCP/IP協(xié)議斟赚。 實(shí)際上着降,Socket跟TCP/IP協(xié)議沒有必然的聯(lián)系。Socket編程接口在設(shè)計的時候拗军,就希望也能適應(yīng)其他的網(wǎng)絡(luò)協(xié)議任洞。所以說,Socket的出現(xiàn) 只是使得程序員更方便地使用TCP/IP協(xié)議棧而已发侵,是對TCP/IP協(xié)議的抽象侈咕,從而形成了我們知道的一些最基本的函數(shù)接口,比如create器紧、 listen、connect楼眷、accept铲汪、send熊尉、read和write等等。

在這里我就著重講下IOS端的使用和問題

使用到的是CocoaAsyncSocket 中的GCDAsyncSocket (當(dāng)然CocoaAsyncSocket里也有創(chuàng)建UDP的就不累述)

  • 創(chuàng)建鏈接 以及對應(yīng)的回調(diào)

//建立鏈接
TcpClient *tcp = [TcpClient sharedInstance];
[tcp setDelegate_ITcpClient:self];
if(tcp.asyncSocket.isConnected)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:@"網(wǎng)絡(luò)已經(jīng)連接好啦掌腰!" delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil];
[alert show];
}else
{
[tcp openTcpConnection:HOST port:[PORT intValue]];
}
這里的TcpClient 是擁有GCDAsyncSocket屬性的單例 從中可以看到連接的時候只是需要HOST 和 port 就是地址和端口

   - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
    {
     DLog(@"鏈接成功啦socket:%p didConnectToHost:%@ port:%hu", sock, host, port);
    [[NSNotificationCenter defaultCenter] postNotificationName:@"didConnectToHost" object:nil userInfo:nil];
    if ([itcpClient respondsToSelector:@selector(didConnectToHost)]) {
        [itcpClient didConnectToHost];
    }
    [self read];
    } 


   - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
     {

     if (err) {
    DLog(@"連接失敗");
    dispatch_async(dispatch_get_main_queue(), ^{
        if ([itcpClient respondsToSelector:@selector(OnConnectionError:)]) {
            [itcpClient OnConnectionError:err];
        }
        
    });
     }else{
    DLog(@"正常斷開");
   }
   } 
  • 發(fā)送消息

     // 進(jìn)入微課
              NSDictionary *params = @{@"requestCode":@"10001",@"token":[LoginDataHelper shareInstance].userInfo.token,@"cId":self.model.cId};
              NSString *json = [params JSONString];
              NSString *strn = [NSString stringWithFormat:@"%@\n",json];
              [tcp writeString:strn];
      // TcpClient 中的方法
     -(void)writeString:(NSString*)datastr;
          {
      NSString *requestStr = [NSString stringWithFormat:@"%@",datastr];
    
      NSData *requestData = [requestStr dataUsingEncoding:NSUTF8StringEncoding];
       [self writeData:requestData];
      }
    
     -(void)writeData:(NSData*)data;
     {
      TAG_SEND++;
       [asyncSocket writeData:data withTimeout:-1. tag:TAG_SEND];
      }
    

    當(dāng)然發(fā)送消息也有對應(yīng)的 回調(diào)
    - (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
    {
    DLog(@"發(fā)送消息socket:%p didWriteDataWithTag:%ld", sock, tag);
    [[NSNotificationCenter defaultCenter] postNotificationName:@"didWriteDataWithTag" object:nil userInfo:nil];
    dispatch_async(dispatch_get_main_queue(), ^{
    if ([itcpClient respondsToSelector:@selector(OnSendDataSuccess:)]) {
    [itcpClient OnSendDataSuccess:[NSString stringWithFormat:@"tag:%li",tag]];
    }
    });
    }

  • 收到服務(wù)器的消息

 - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
    {
DLog(@"收到消息啦socket:%p didReadData:withTag:%ld", sock, tag);
     NSString *httpResponse = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    TAG_RECIVED = tag;
     NSDictionary *dic = [NSDictionary dictionaryWithJsonString:httpResponse];
     if (dic) {
    [[NSNotificationCenter defaultCenter] postNotificationName:@"didReadData" object:nil userInfo:dic];
     if(![httpResponse isEqualToString:@""])
    [recivedArray addObject:httpResponse];
    dispatch_async(dispatch_get_main_queue(), ^{
    if ([itcpClient respondsToSelector:@selector(OnReciveData:)]) {
       [itcpClient OnReciveData:dic];
      }       
      });
    }
   [self read];
    } 

當(dāng)然這里你們發(fā)送的消息和接收的消息狰住,前后端要先針對其格式做好對接,定好格式齿梁,按照這個格式去發(fā)送和解析

  • 關(guān)于贝咧玻活問題
    TCP長時間處于非活動狀態(tài)可能會被殺死,所以做好鄙自瘢活是很有必要的
    這里我做的處理是創(chuàng)建心跳機(jī)制 發(fā)送心跳包

       //心跳
    {
     _heartTime = [NSTimer timerWithTimeInterval:50 target:self selector:@selector(reconnectTP) userInfo:nil repeats:YES];
     [[NSRunLoop currentRunLoop] addTimer:self.heartTime forMode:NSDefaultRunLoopMode];
     [_heartTime fire];
     
    }
    
      - (void)reconnectTP{
     TcpClient *tcp = [TcpClient sharedInstance];
     [tcp reconnect];
      {
     
       TcpClient *tcp = [TcpClient sharedInstance];
       if(tcp.asyncSocket.isDisconnected)
       {
          DLog(@"網(wǎng)絡(luò)不通");
          }else if(tcp.asyncSocket.isConnected)
      {
          NSDictionary *params = @{@"requestCode":@"10001",@"token":[LoginDataHelper    shareInstance].userInfo.token,@"cId":self.posterModel.cId};
         NSString *json = [params JSONString];
         NSString *strn = [NSString stringWithFormat:@"%@\n",json];
         [tcp writeString:strn];
         
     }else{
         DLog(@"TCP沒有建立鏈接");
       }
     
       }
     }
    

這里就是定時檢測TCP是否在連線狀態(tài)创南,如果不在就重連,如果在就發(fā)送心跳包給后臺省核。從而保證TCP的活性

  • 中間出現(xiàn)過的問題
    開始我們的TCP一直都很正常稿辙,但是在服務(wù)器集群之后就出現(xiàn)問題了,IOS怎么也接收不到服務(wù)器發(fā)送的消息气忠,鏈接很正常就是收不到消息邻储,但是安卓卻沒有任何問題,當(dāng)初這個問題困擾我們了很久旧噪,大家都把責(zé)任推到IOS 這邊吨娜,當(dāng)時我也是倍感壓力,很不解淘钟,為啥之前就行宦赠,集群之后就出現(xiàn)問題了呢,后來經(jīng)過我不斷地努力和測試才發(fā)現(xiàn)問題是:
    服務(wù)端在發(fā)送消息之后并沒有用\r\n 或者\(yùn)n 作為結(jié)束標(biāo)志日月,這在之前是沒問題的袱瓮,但是集群之后在Ruby語言里面就出現(xiàn)問題,沒有結(jié)束標(biāo)志爱咬,IOS這邊就一直收不到消息尺借。因?yàn)樗恢闭J(rèn)為在傳送數(shù)據(jù)沒有結(jié)束。
    # 所以一定要在發(fā)送消息之后以\r\n或者\(yùn)n 作為結(jié)束符,避免不必要的麻煩精拟。

目前只想起來這些燎斩,至于其他問題,可以留言給我蜂绎,我們公共探討栅表,也可以加我的Q:719967870,下面我貼出 基于GCDAsyncSocket封裝的單例大家可以直接使用

    //  TcpClient.h
   //  ConnectTest
   //
  //  Created by  yuchen on 2016.

   #import <Foundation/Foundation.h>
   #import "GCDAsyncSocket.h"
   #import "ITcpClient.h"
          
@interface TcpClient : NSObject
  {
              long TAG_SEND;
              long TAG_RECIVED;
              id<ITcpClient> itcpClient;
              NSMutableArray *recivedArray;
  }

  @property (nonatomic,retain) GCDAsyncSocket *asyncSocket;
 + (TcpClient *)sharedInstance;
  -(void)setDelegate_ITcpClient:(id<ITcpClient>)_itcpClient;
  // 鏈接
  -(void)openTcpConnection:(NSString*)host port:(NSInteger)port;
  -(void)reconnect ;
  -(void)read;
  //發(fā)消息
  -(void)writeString:(NSString*)datastr;
  -(void)writeData:(NSData*)data;
  -(long)GetSendTag;
  -(long)GetRecivedTag;
  //斷開
  -(void)disconnect;
   @end

//.m

 //  TcpClient.m
  //  ConnectTest
   //
   //  Created by  yuchen on 2016.
   //
  //
        
#import "TcpClient.h"
#import "GCDAsyncSocket.h"
#import "LZ_DevKit.h"
#import "NSDictionary+JSON.h"
@implementation TcpClient
@synthesize asyncSocket;

+ (TcpClient *)sharedInstance;
{
    static TcpClient *_sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedInstance = [[TcpClient alloc] init];
    });

    return _sharedInstance;
}


-(id)init;
{
    self = [super init];
    recivedArray = [NSMutableArray arrayWithCapacity:10];
    return self;
}

-(void)setDelegate_ITcpClient:(id<ITcpClient>)_itcpClient;
{
itcpClient = _itcpClient;
}

-(void)openTcpConnection:(NSString*)host port:(NSInteger)port;
{



//  dispatch_queue_create("bin.queue", DISPATCH_QUEUE_SERIAL);
//  dispatch_queue_t mainQueue = dispatch_get_main_queue();
    dispatch_queue_t mainQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
    asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:mainQueue];

    [asyncSocket setAutoDisconnectOnClosedReadStream:NO];

      NSError *error = nil;
        if (![asyncSocket connectToHost:host onPort:port error:&error])
        {
        DLog(@"Error connecting: %@", error);

    }



}
-(void)disconnect{

    itcpClient = nil;
     [asyncSocket setDelegate:nil delegateQueue:NULL];
    [asyncSocket disconnect];




}

//  重新連接
-(void)reconnect {
    NSError* err;
    if([asyncSocket isDisconnected]) {
    
       BOOL  result = [asyncSocket connectToHost:HOST onPort:[PORT integerValue]  error:&err];
    
        if(result)
        {
            DLog(@"重新連接--主機(jī)%@-Port%@",HOST,PORT);
        
 
        }
        else {
            DLog(@"連接失敗ERROR %@",[err description]);
        }
    
    }else{
        DLog(@"已經(jīng)連接");
    }
}

-(void)writeString:(NSString*)datastr;
{
    NSString *requestStr = [NSString stringWithFormat:@"%@",datastr];

    NSData *requestData = [requestStr dataUsingEncoding:NSUTF8StringEncoding];
    [self writeData:requestData];
}

-(void)writeData:(NSData*)data;
{
    TAG_SEND++;
    [asyncSocket writeData:data withTimeout:-1. tag:TAG_SEND];
}

-(void)read;
{
    [asyncSocket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];

}

    -(long)GetSendTag;
{
    return TAG_SEND;
}

-(long)GetRecivedTag;
{
return TAG_RECIVED;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Socket Delegate
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////??哈哈

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
    DLog(@"鏈接成功啦socket:%p didConnectToHost:%@ port:%hu", sock, host, port);
    [[NSNotificationCenter defaultCenter] postNotificationName:@"didConnectToHost" object:nil userInfo:nil];
    if ([itcpClient respondsToSelector:@selector(didConnectToHost)]) {
        [itcpClient didConnectToHost];
    }
    [self read];

    }
//是否加密
- (void)socketDidSecure:(GCDAsyncSocket *)sock
{
DLog(@"socketDidSecure:%p", sock);


NSString *requestStr = [NSString stringWithFormat:@"GET / HTTP/1.1\r\nHost: %@\r\n\r\n", HOST];
NSData *requestData = [requestStr dataUsingEncoding:NSUTF8StringEncoding];

    [sock writeData:requestData withTimeout:-1 tag:0];
    [sock readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];
}

- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
DLog(@"發(fā)送消息socket:%p didWriteDataWithTag:%ld", sock, tag);
 [[NSNotificationCenter defaultCenter] postNotificationName:@"didWriteDataWithTag" object:nil userInfo:nil];
dispatch_async(dispatch_get_main_queue(), ^{
    if ([itcpClient respondsToSelector:@selector(OnSendDataSuccess:)]) {
    [itcpClient OnSendDataSuccess:[NSString stringWithFormat:@"tag:%li",tag]];
    }
  
});
}

- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
    DLog(@"收到消息啦socket:%p didReadData:withTag:%ld", sock, tag);
 
    NSString *httpResponse = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    TAG_RECIVED = tag;

    NSDictionary *dic = [NSDictionary dictionaryWithJsonString:httpResponse];
if (dic) {

    [[NSNotificationCenter defaultCenter] postNotificationName:@"didReadData" object:nil userInfo:dic];

    if(![httpResponse isEqualToString:@""])
    [recivedArray addObject:httpResponse];

    dispatch_async(dispatch_get_main_queue(), ^{
    if ([itcpClient respondsToSelector:@selector(OnReciveData:)]) {
       [itcpClient OnReciveData:dic];
        }
   
    });

    }
    [self read];


}

- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{

    if (err) {
    DLog(@"連接失敗");
    dispatch_async(dispatch_get_main_queue(), ^{
        if ([itcpClient respondsToSelector:@selector(OnConnectionError:)]) {
            [itcpClient OnConnectionError:err];
        }
        
    });
}else{
    DLog(@"正常斷開");
    }

}

- (void)socketDidCloseReadStream:(GCDAsyncSocket *)sock
{

}
@end

CocoaAsyncSocket :https://github.com/robbiehanson/CocoaAsyncSocket

好了文章就到這里了謝謝大家师枣!大家也可以加Q 群 229309298 一個iOS學(xué)習(xí)交流群

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末怪瓶,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子践美,更是在濱河造成了極大的恐慌洗贰,老刑警劉巖找岖,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異敛滋,居然都是意外死亡许布,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門绎晃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蜜唾,“玉大人,你說我怎么就攤上這事庶艾≡啵” “怎么了?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵落竹,是天一觀的道長泌霍。 經(jīng)常有香客問我,道長述召,這世上最難降的妖魔是什么朱转? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮积暖,結(jié)果婚禮上藤为,老公的妹妹穿的比我還像新娘。我一直安慰自己夺刑,他們只是感情好缅疟,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著遍愿,像睡著了一般存淫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沼填,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天桅咆,我揣著相機(jī)與錄音,去河邊找鬼坞笙。 笑死岩饼,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的薛夜。 我是一名探鬼主播籍茧,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼梯澜!你這毒婦竟也來了寞冯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎吮龄,沒想到半個月后檬某,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡螟蝙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了民傻。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胰默。...
    茶點(diǎn)故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖漓踢,靈堂內(nèi)的尸體忽然破棺而出牵署,到底是詐尸還是另有隱情,我是刑警寧澤喧半,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布奴迅,位于F島的核電站,受9級特大地震影響挺据,放射性物質(zhì)發(fā)生泄漏取具。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一扁耐、第九天 我趴在偏房一處隱蔽的房頂上張望暇检。 院中可真熱鬧,春花似錦婉称、人聲如沸块仆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽悔据。三九已至,卻和暖如春俗壹,著一層夾襖步出監(jiān)牢的瞬間科汗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工策肝, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留肛捍,地道東北人。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓之众,卻偏偏與公主長得像拙毫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子棺禾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評論 2 353

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