Reachability類的學(xué)習(xí)

Reachability類的學(xué)習(xí)

簡介

Reachability類是Apple官方出的判斷當(dāng)前網(wǎng)絡(luò)狀況的工具類,這個庫一直在隨著iOS的版本在更新,目前iOS10對應(yīng)的最新版本是5.0

Reachability_xcodeproj.png

官方說明文檔分為四部分

簡介

The Reachability sample application demonstrates how to use the System Configuration framework to monitor the network state of an iOS device. In particular, it demonstrates how to know when IP can be routed and when traffic will be routed through a Wireless Wide Area Network (WWAN) interface such as EDGE or 3G.

Note: Reachability cannot tell your application if you can connect to a particular host, only that an interface is available that might allow a connection, and whether that interface is the WWAN. To understand when and how to use Reachability, read [Networking Overview][1].[1]: http://developer.apple.com/library/ios/#documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/

  • 總結(jié)
    Reachability能判斷網(wǎng)路路由狀態(tài),包括2G/3G等狀態(tài)。

  • 這里有兩個問題

  1. 什么是路由?

這是TCP網(wǎng)絡(luò)層尋址的一個概念,通俗的講就是是否有對應(yīng)的IP或者host(多一層DNS解析)是否在網(wǎng)絡(luò)上存在。而然也僅僅是只能判斷出是否存在,無法知道更多信息。例如:丟包率(ping 100% lost照樣算可達狀態(tài))。更不可能判斷當(dāng)前需要的服務(wù)是否可用,例如:login接口是否可用?

  1. 可以判斷出有網(wǎng)狀態(tài)下是否是2G/3G/4G

可以判斷出,然而本工具并未集成.

IPV6支持

Reachability fully supports IPv6. More specifically, each of the APIs handles IPv6 in the following way:

  • reachabilityWithHostName and SCNetworkReachabilityCreateWithName: Internally, this API works be resolving the host name to a set of IP addresses (this can be any combination of IPv4 and IPv6 addresses) and establishing separate monitors on all available addresses.
  • reachabilityWithAddress and SCNetworkReachabilityCreateWithAddress: To monitor an IPv6 address, simply pass in an IPv6 sockaddr_in6 struct instead of the IPv4 sockaddr_in struct.
  • reachabilityForInternetConnection: This monitors the address 0.0.0.0, which reachability treats as a special token that causes it to actually monitor the general routing status of the device, both IPv4 and IPv6.
  • 總結(jié)
    reachabilityWithHostNameSCNetworkReachabilityCreateWithName網(wǎng)址/IP均可以直接支持。
    reachabilityWithAddressSCNetworkReachabilityCreateWithAddress要吃支持IPv6需要替換對應(yīng)數(shù)據(jù)結(jié)構(gòu),用sockaddr_in6 struct替換sockaddr_in struct
    reachabilityForInternetConnection監(jiān)控的是0.0.0.0地址,IPv4,IPv6一起支持

  • 問題

  1. 支持IPv6,但是工具類里邊沒有對應(yīng)代碼,要自己實現(xiàn)
  2. reachabilityForInternetConnection監(jiān)控的0.0.0.0是什么意思?
    看解釋

Checks whether the default route is available. Should be used by applications that do not connect to a particular host.

在沒有特定網(wǎng)址需要探測的情況下,判斷路由是否可達。通俗的說就是沒開飛行模式,網(wǎng)絡(luò)模塊沒壞。

移除reachabilityForLocalWiFi

Older versions of this sample included the method reachabilityForLocalWiFi. As originally designed, this method allowed apps using Bonjour to check the status of "local only" Wi-Fi (Wi-Fi without a connection to the larger internet) to determine whether or not they should advertise or browse.

However, the additional peer-to-peer APIs that have since been added to iOS and OS X have rendered it largely obsolete. Because of the narrow use case for this API and the large potential for misuse, reachabilityForLocalWiFi has been removed from Reachability.

Apps that have a specific requirement can use reachabilityWithAddress to monitor IN_LINKLOCALNETNUM (that is, 169.254.0.0).

Note: ONLY apps that have a specific requirement should be monitoring IN_LINKLOCALNETNUM. For the overwhelming majority of apps, monitoring this address is unnecessary and potentially harmful.

  • 總結(jié)
    講了reachabilityForLocalWiFi的原理,監(jiān)控一個特殊IP鏈路本地地址(169.254.0.0)來判斷WIFI沒有連上互聯(lián)網(wǎng)的時候WIFI狀態(tài)。Apple認為新出來的點對點啥的,這個函數(shù)判斷不出來,還容易誤導(dǎo)大家。干脆給刪除了,干得漂亮。這個API只能探測到是否連接上WIFI(不包括AP),沒WIFI用WLan也返回沒網(wǎng)。

用法

Build and run the sample using Xcode. When running the iPhone Simulator, you can exercise the application by disconnecting the Ethernet cable, turning off AirPort, or by joining an ad-hoc local Wi-Fi network.

By default, the application uses www.apple.com for its remote host. You can change the host it uses in APLViewController.m by modifying the value of the remoteHostName variable in -viewDidLoad.

IMPORTANT: Reachability must use DNS to resolve the host name before it can determine the Reachability of that host, and this may take time on certain network connections. Because of this, the API will return NotReachable until name resolution has completed. This delay may be visible in the interface on some networks.

The Reachability sample demonstrates the asynchronous use of the SCNetworkReachability API. You can use the API synchronously, but do not issue a synchronous check by hostName on the main thread. If the device cannot reach a DNS server or is on a slow network, a synchronous call to the SCNetworkReachabilityGetFlags function can block for up to 30 seconds trying to resolve the hostName. If this happens on the main thread, the application watchdog will kill the application after 20 seconds of inactivity.

SCNetworkReachability API's do not currently provide a means to detect support for device level peer-to-peer networking, including Multipeer Connectivity, GameKit, Game Center, or peer-to-peer NSNetService.

  • 總結(jié)
  1. Reachability提供了同步,異步兩個版本的判斷當(dāng)前網(wǎng)絡(luò)狀態(tài)的方法,同步會有坑,如果在主線程調(diào)用SCNetworkReachabilityGetFlags相關(guān)的API(其實就是connectionRequiredcurrentReachabilityStatus)DNS或者網(wǎng)絡(luò)狀況比較差的話,超過30秒沒反應(yīng),看門狗程序會早程序20秒未響應(yīng)的情況下,會殺死本應(yīng)用。
  2. Reachability判斷不了P2P,包括Multipeer Connectivity, GameKit, Game Center, or peer-to-peer NSNetService.

擴展

  1. 增加2G/3G/4G判斷
    第一種方法

  • (void)getNetworkType
    {
    UIApplication *app = [UIApplication sharedApplication];
    NSArray *subviews = [[[app valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];
    for (id subview in subviews) {
    if ([subview isKindOfClass:NSClassFromString(@"UIStatusBarDataNetworkItemView")]) {
    int networkType = [[subview valueForKeyPath:@"dataNetworkType"] intValue];
    switch (networkType) {
    case 0:
    NSLog(@"NONE");
    break;
    case 1:
    NSLog(@"2G");
    break;
    case 2:
    NSLog(@"3G");
    break;
    case 3:
    NSLog(@"4G");
    break;
    case 5:
    {
    NSLog(@"WIFI");
    }
    break;
    default:
    break;
    }
    }
    }
    }

    **第二種**
    

    if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
    {
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)
    {

         CTTelephonyNetworkInfo * info = [[CTTelephonyNetworkInfo alloc] init];
         NSString *currentRadioAccessTechnology = info.currentRadioAccessTechnology;
         if (currentRadioAccessTechnology)
         {
             if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyLTE])
             {
                 returnValue =  kReachableVia4G;
             }
             else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyEdge] || [currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyGPRS])
             {
                 returnValue =  kReachableVia2G;
             }
             else
             {
                 returnValue =  kReachableVia3G;
             }
             return returnValue;
    
         }
     }
    
     if ((flags & kSCNetworkReachabilityFlagsTransientConnection) == kSCNetworkReachabilityFlagsTransientConnection)
     {
         if((flags & kSCNetworkReachabilityFlagsConnectionRequired) == kSCNetworkReachabilityFlagsConnectionRequired)
         {
             returnValue =  kReachableVia2G;
             return returnValue;
         }
         returnValue =  kReachableVia3G;
         return returnValue;
     }
    
     returnValue = ReachableViaWWAN;
    

    }

  1. 支持IPv6
  2. 防止應(yīng)用被殺死
  3. 關(guān)于Reachability的使用
  4. 網(wǎng)絡(luò)信號強度判斷
    黑魔法,使用狀態(tài)欄來判斷
- (void)getSignalStrength{
    UIApplication *app = [UIApplication sharedApplication];
    NSArray *subviews = [[[app valueForKey:@"statusBar"] valueForKey:@"foregroundView"] subviews];
    NSString *dataNetworkItemView = nil;
    
    for (id subview in subviews) {
        if([subview isKindOfClass:[NSClassFromString(@"UIStatusBarDataNetworkItemView") class]]) {
            dataNetworkItemView = subview;
            break;
        }
    }
    
    int signalStrength = [[dataNetworkItemView valueForKey:@"_wifiStrengthBars"] intValue];
    
    NSLog(@"signal %d", signalStrength);
}

測試

適配支持驗證方法

測試驗證方式就是通過Mac的共享網(wǎng)絡(luò)共享一個IPv6的無線網(wǎng),跟已往創(chuàng)建方式不同的是進入共享時需要按住Option鍵,不然Create NAT64 Network的選項不會出現(xiàn)

1475116819.png

然后開啟無線共享,使iPhone連接上分享出來的熱點即可 注:需要將iPhone的蜂窩網(wǎng)絡(luò)數(shù)據(jù)關(guān)掉,以保證只有通過WiFi在連接網(wǎng)絡(luò)。

使用誤區(qū)

  • 以下是一段錯誤,用法
        self.reachAbility = [Reachability reachabilityForLocalWiFi];
        [self.reachAbility startNotifier];
        NetworkStatus netStatus = [self.reachAbility currentReachabilityStatus];
        if (ReachableViaWiFi == netStatus)
        {   DEBUGLOG(@"wifi statu");
            [[UploadLogManager shareManager] startUploadLog];
        }

解析:

  1. 初始化不合理

相關(guān)代碼段

 self.reachAbility = [Reachability reachabilityForLocalWiFi];

分析

reachabilityForLocalWiFi已經(jīng)在最新的版本被廢止,原因就是他的局限性,只能判斷出本地WIFI是否可用,重點是本地也就是說無法判斷出WIFI是否聯(lián)網(wǎng)。一般情況下,不實用此API,應(yīng)該用reachabilityForInternetConnection

  1. 同步獲取狀態(tài)不合理
    相關(guān)代碼段
 NetworkStatus netStatus = [self.reachAbility currentReachabilityStatus];

Apple Documents解釋

The SCNetworkReachability programming interface allows an application to determine the status of a system's current network configuration and the reachability of a target host. A remote host is considered reachable when a data packet, sent by an application into the network stack, can leave the local device. Reachability does not guarantee that the data packet will actually be received by the host.

The SCNetworkReachability programming interface supports a synchronous and an asynchronous model. In the synchronous model, you get the reachability status by calling the SCNetworkReachabilityGetFlags function. In the asynchronous model, you can schedule the SCNetworkReachability object on the run loop of a client object’s thread. The client implements a callback function to receive notifications when the reachability status of a given remote host changes. Note that these functions follow Core Foundation naming conventions. A function that has "Create" or "Copy" in its name returns a reference you must release with the CFRelease function.


分析

獲取網(wǎng)絡(luò)狀態(tài),有同步異步兩種。使用startNotifier代表使用異步方式,獲取狀態(tài)應(yīng)該先注冊通知kReachabilityChangedNotification在回調(diào)之后,調(diào)用currentReachabilityStatus才能正確獲取,在這里直接調(diào)用第一次獲取只能是默認狀態(tài)NotReachable,其實實在獲取中,這樣用不夠準(zhǔn)確。

正確做法

  1. 使用異步方式
  • 初始化

       [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil];
    
  • 注冊通知

    NSString *remoteHostName = @"https://twitter.com";
    self.hostReachability = [Reachability reachabilityWithHostName:remoteHostName];
  • 開始監(jiān)控
[self.hostReachability startNotifier];
  • 回調(diào)處理
- (void) reachabilityChanged:(NSNotification *)note
{
    Reachability* curReach = [note object];
    NSParameterAssert([curReach isKindOfClass:[Reachability class]]);
    [self updateInterfaceWithReachability:curReach];
}
  1. 使用同步方式
  • 初始化
 self.internetReachability = [Reachability reachabilityForInternetConnection];
  • 獲取狀態(tài)
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NetworkStatus netStatus = [self.hostReachability currentReachabilityStatus];
        NSString *tips = [self syncGetNetStatus:netStatus];
        dispatch_async(dispatch_get_main_queue(), ^{
            syncLabel.text = [NSString stringWithFormat:@"同步探測結(jié)果:%@",tips];
        });
    });

封裝

代碼

  • TSReachabilityManager.h
#import <Foundation/Foundation.h>
#import "Reachability.h"

@(原創(chuàng)整理)interface TSReachabilityManager : NSObject

@property (nonatomic, strong) NSString *remoteHostName;

+ (instancetype)shareManager;

- (NetworkStatus)currentReachabilityStatus;

- (NSString*)netStatusDescription;

@end
  • TSReachabilityManager.m
#import "TSReachabilityManager.h"


static TSReachabilityManager *gTSReachabilityManager = nil;

@interface TSReachabilityManager ()

@property (nonatomic, strong) NSThread *reachabilityDaemonThread;
@property (nonatomic) Reachability *internetReachability;
@property (nonatomic, assign) BOOL isGotStatus;
@end

@implementation TSReachabilityManager

+ (instancetype)shareManager;
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        gTSReachabilityManager = [[TSReachabilityManager alloc] init];
        [gTSReachabilityManager _setup];
    });
    
    return gTSReachabilityManager;
}

- (void)_setup
{
    _isGotStatus = NO;
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(reachabilityChanged:)
                                                 name:kReachabilityChangedNotification
                                               object:nil];
    
    //能夠快速判斷出本機的連接狀況,未連接、WIFI、WLan
    self.internetReachability = [Reachability reachabilityForInternetConnection];
    [self.internetReachability startNotifier];
}


/*!
 * Called by Reachability whenever status changes.
 */
- (void) reachabilityChanged:(NSNotification *)note
{
    _isGotStatus = YES;
    Reachability* curReach = [note object];
    NSParameterAssert([curReach isKindOfClass:[Reachability class]]);
    [self updateInterfaceWithReachability:curReach];
    
}

- (NetworkStatus)currentReachabilityStatus;
{
    if(_isGotStatus)
    {
        return [self.internetReachability currentReachabilityStatus];
    }
    return kReachableUnkown;
}

- (NSString*)netStatusDescription
{
    NetworkStatus netStatus = [self currentReachabilityStatus];
    NSString *tips = @"";
    switch (netStatus)
    {
        case NotReachable:
            tips = @"無網(wǎng)絡(luò)連接";
            break;
            
        case ReachableViaWiFi:
            tips = @"Wifi";
            break;
            
        case ReachableViaWWAN:
            NSLog(@"移動流量");
        case kReachableVia2G:
            tips = @"2G";
            break;
            
        case kReachableVia3G:
            tips = @"3G";
            break;
            
        case kReachableVia4G:
            tips = @"4G";
            break;
        default:
            tips = @"正在獲取狀態(tài)";
    }
    return tips;
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:kReachabilityChangedNotification object:nil];
}

@end

用法舉例

- (void)startRequest
{
    NSString *URLString = @"http://192.168.43.1:8080/cateye/Status";
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
    
    NSURLRequest *request =
    [[AFHTTPRequestSerializer serializer] requestWithMethod:@"GET" URLString:URLString parameters:nil error:nil];;
    
    NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
        if (error) {
            NSLog(@"Error: %@", error);
            //獲取當(dāng)前網(wǎng)絡(luò)狀態(tài)
            NetworkStatus status = [[TSReachabilityManager shareManager] currentReachabilityStatus];
            //彈出斷網(wǎng)alert/tips/toast等等
            if(status == NotReachable)
            {
                
            }
        } else {
            NSLog(@"%@ %@", response, responseObject);
        }
    }];
    [dataTask resume];
}

彩蛋

  • 使用AP模式,注意左上角顯示4G,但是reachabilityWithHostName顯示W(wǎng)IFI,reachabilityForInternetConnection顯示網(wǎng)絡(luò)連接狀態(tài)4G,跟左上角保持一致,reachabilityForLocalWiFi認為無網(wǎng)絡(luò),因為沒用WIFI連接。
ScreenShot_20161011093447.png

設(shè)置里能看出連著AP

ScreenShot_20161011093514.png
  • 更新說明

    經(jīng)過討論,使用后臺線程可完全避免被看門狗殺死APP,方案以及用法如下:

#import <Foundation/Foundation.h>
#import "Reachability.h"

extern NSString *kTSReachabilityChangedNotification;

@interface TSReachabilityManager : NSObject

@property (nonatomic, strong) NSString *remoteHostName;

+ (instancetype)shareManager;

- (void)startMonitor;

@end
#import "TSReachabilityManager.h"


NSString *kTSReachabilityChangedNotification = @"kTSNetworkReachabilityChangedNotification";


static TSReachabilityManager *gTSReachabilityManager = nil;

@interface TSReachabilityManager ()

@property (nonatomic, strong) NSThread *reachabilityDaemonThread;
@property (nonatomic) Reachability *internetReachability;
@property (nonatomic, assign) NetworkStatus currentReachabilityStatus;
@end

@implementation TSReachabilityManager

+ (instancetype)shareManager;
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        gTSReachabilityManager = [[TSReachabilityManager alloc] init];
        [gTSReachabilityManager _setup];
    });
    
    return gTSReachabilityManager;
}

- (void)_setup
{
    _remoteHostName = @"www.baidu.com";
    [self startMonitor];
}

- (void)startMonitor
{
    //啟動守護線程,防止服務(wù)器在長時間無響應(yīng)導(dǎo)致的看門狗殺死app的情形發(fā)生
    _reachabilityDaemonThread = [[NSThread alloc] initWithTarget:self selector:@selector(monitorNetReachability) object:nil];
    [_reachabilityDaemonThread start];
    
}

- (void)monitorNetReachability
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil];
    
    //Change the host name here to change the server you want to monitor.

    //能夠判斷出遠程服務(wù)器時候可達,ping不通的時候,還是wifi連接狀態(tài)。服務(wù)器狀態(tài)還是用接口返回情況來判斷準(zhǔn)確,只有需要判斷connectionRequired的時候才用host
    self.internetReachability = [Reachability reachabilityWithHostName:_remoteHostName];
    [self.internetReachability startNotifier];
    
    
    //保持線程不退出
    [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSRunLoopCommonModes];
    [[NSRunLoop currentRunLoop] run];
    
    _currentReachabilityStatus = [self currentReachabilityStatus];
    dispatch_async(dispatch_get_main_queue(), ^{
        NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:_currentReachabilityStatus],@"status",[self netStatusDescription],@"description", nil];
         [[NSNotificationCenter defaultCenter] postNotificationName:kTSReachabilityChangedNotification object:self userInfo:dic];
    });

}


/*!
 * Called by Reachability whenever status changes.
 */
- (void) reachabilityChanged:(NSNotification *)note
{
    Reachability* curReach = [note object];
    NSParameterAssert([curReach isKindOfClass:[Reachability class]]);
    _currentReachabilityStatus = [curReach currentReachabilityStatus];
    dispatch_async(dispatch_get_main_queue(), ^{
        NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:_currentReachabilityStatus],@"status",[self netStatusDescription],@"description", nil];
        [[NSNotificationCenter defaultCenter] postNotificationName:kTSReachabilityChangedNotification object:self userInfo:dic];
    });
}



- (NSString*)netStatusDescription
{
    NetworkStatus netStatus = [self currentReachabilityStatus];
    NSString *tips = @"";
    switch (netStatus)
    {
        case NotReachable:
            tips = @"無網(wǎng)絡(luò)連接";
            break;
            
        case ReachableViaWiFi:
            tips = @"Wifi";
            break;
            
        case ReachableViaWWAN:
            NSLog(@"移動流量");
        case kReachableVia2G:
            tips = @"2G";
            break;
            
        case kReachableVia3G:
            tips = @"3G";
            break;
            
        case kReachableVia4G:
            tips = @"4G";
            break;
        default:
            tips = @"正在獲取狀態(tài)";
    }
    return tips;
}




- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:kReachabilityChangedNotification object:nil];
}

@end

調(diào)用方法:

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_showNetStatus:) name:kTSReachabilityChangedNotification object:nil];
    [[TSReachabilityManager shareManager] startMonitor];
}

- (void)_showNetStatus:(NSNotification*)aNo
{
    NSLog(@"userInfo:%@",[aNo.userInfo objectForKey:@"description"]);
}

代碼:

代碼附件在印象筆記,后邊有需要再傳。

代碼放在git上了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,963評論 6 542
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,348評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,083評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,706評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,442評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,802評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,795評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,983評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,542評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,287評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,486評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,030評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,710評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,116評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,412評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,224評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,462評論 2 378

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