XMPP搭建本地服務(wù)器、實現(xiàn)即時通訊(二)

前面部分呢,我們實現(xiàn)了一個XMPP本地服務(wù)器的搭建http://www.lxweimin.com/p/86eeb47d1792 但是我們最終的目的并不是這些,我們是要實現(xiàn)即時通訊的功能,今天我們就在代碼里面實現(xiàn)即時通訊的基本功能。

一、項目環(huán)境配置

  • 首先我們在工程中導(dǎo)入XMPPFramework


    導(dǎo)入 XMPPFramework
  • 添加本地依賴庫:libxml2.tbd和libresolv.tbd


    添加本地庫
  • 然后Build Settings->Header searches Pathes添加字段:/usr/include/libxml2


    添加字段
  • Commend+B編譯正常的話就OK了

二、建立與服務(wù)器的鏈接

  • 我們在建立與服務(wù)器鏈接之前需要自己創(chuàng)建:登陸頁面,注冊頁面,好友列表頁面和聊天頁面,這些在此不再累述,想必大家用可視化,分分鐘搞定。至于各個頁面之間的關(guān)聯(lián),更是小kiss
  • 我們需要建立一個XMPP的任務(wù)管理類對象 而且這個對象只需要一個 我們可以用單例:
.h
@interface XMPPManager : NSObject<XMPPStreamDelegate>

+(XMPPManager *)sharedXMPPManager;//創(chuàng)建管理者對象單例

@property(nonatomic,strong)XMPPStream *stream;//信息管道
@property(nonatomic,strong)XMPPRoster *xmppRoster;//進行添加好友 刪除好友 獲取還有列表等功能
@property(nonatomic,strong)XMPPMessageArchiving *xmppMessageArchivering;

@property(nonatomic,strong)NSManagedObjectContext *messageManagerContext;//聊天信息托管對象 上下文

//登陸
-(void)loginWithUser:(NSString *)user password:(NSString *)password;

//注冊
-(void)registWithUser:(NSString *)user password:(NSString *)password;
@end

.m
#import "XMPPManager.h"
//判斷想服務(wù)器建立連接是登陸還是注冊
typedef enum : NSUInteger {
    ConnectToServerPurposeLogin,//登陸
    ConnectToServerPurposeRegist,//注冊
} MyStatus;

@interface XMPPManager ()
@property(nonatomic,strong)NSString *password;//登錄密碼
@property(nonatomic,strong)NSString *registPassword;//注冊密碼
@property(nonatomic,assign)MyStatus connectToServerPurse;
@end
@implementation XMPPManager

+(XMPPManager *)sharedXMPPManager{
    static XMPPManager *manager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[XMPPManager alloc]init];
    });
    return manager;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.stream = [[XMPPStream alloc]init];
        self.stream.hostName = kHostName;//服務(wù)器的地址
        self.stream.hostPort = kHostPort;//端口號標識唯一的服務(wù)
        [self.stream addDelegate:self delegateQueue:dispatch_get_main_queue()];//讓當(dāng)前對象成為stream的代理
        
        
        //進行好友存儲
        XMPPRosterCoreDataStorage *storage= [XMPPRosterCoreDataStorage sharedInstance];
        self.xmppRoster = [[XMPPRoster alloc]initWithRosterStorage:storage dispatchQueue:dispatch_get_main_queue()];
        [self.xmppRoster activate:self.stream];//激活
        
        
        //進行聊天信息存儲
        XMPPMessageArchivingCoreDataStorage *archiveringStorage = [XMPPMessageArchivingCoreDataStorage sharedInstance];
        self.xmppMessageArchivering = [[XMPPMessageArchiving alloc]initWithMessageArchivingStorage:archiveringStorage dispatchQueue:dispatch_get_main_queue()];
        [self.xmppMessageArchivering activate:self.stream];//激活
        
        self.messageManagerContext = archiveringStorage.mainThreadManagedObjectContext;
    }
    return self;
}

//與服務(wù)器建立鏈接
-(void)connectToServerWithUser:(NSString *)user{
    //要是正在鏈接的話那么就先斷開連接
    if ([self.stream isConnected]) {
        [self disconnectServer];
    }
    XMPPJID *jid = [XMPPJID jidWithUser:user domain:kDomin resource:kResource];
    self.stream.myJID = jid;
    NSError *error = nil;
    [self.stream connectWithTimeout:30.0f error:&error];
    if (nil != error) {
        NSLog(@"%s__%d__鏈接出錯:%@",__FUNCTION__,__LINE__,error);
    }
}
//與服務(wù)器斷開鏈接
-(void)disconnectServer{
    [self.stream disconnect];
}
//登陸
-(void)loginWithUser:(NSString *)user password:(NSString *)password{
    
    self.connectToServerPurse = ConnectToServerPurposeLogin;
    self.password = password;//將傳進來的password傳給self.password
    [self connectToServerWithUser:user];
}
//注冊
-(void)registWithUser:(NSString *)user password:(NSString *)password{
    self.connectToServerPurse = ConnectToServerPurposeRegist;
    self.registPassword = password;
    [self connectToServerWithUser:user];
}

#pragma mark--XMPPStreamDelegate
//我們一旦想服務(wù)器發(fā)送請求之后又兩種結(jié)果 成功和失敗 我們需要實現(xiàn)XMPP協(xié)議的兩個方法
//與服務(wù)器鏈接成功
-(void)xmppStreamDidConnect:(XMPPStream *)sender{
    
    NSLog(@"%s__%d__",__FUNCTION__,__LINE__);
    
#pragma mark ------判斷與服務(wù)器建立連接是登陸還是注冊
    switch (self.connectToServerPurse) {
        case ConnectToServerPurposeLogin:
        {
            //建立連接成功之后需要向服務(wù)器驗證自己的身份
            NSError *error = nil;
            [self.stream authenticateWithPassword:self.password error:&error];
            if (nil != error) {
                NSLog(@"%s__%d__驗證出錯:%@",__FUNCTION__,__LINE__,error);
            }
            break;
        }
        case ConnectToServerPurposeRegist:
        {
            NSError *err = nil;
            [self.stream registerWithPassword:self.registPassword error:&err];
            if (nil != err) {
                NSLog(@"%s__%d__注冊出錯:%@",__FUNCTION__,__LINE__,err);
            }
            break;
        }
        default:
            break;
    }
}
//與服務(wù)器鏈接失敗
-(void)xmppStreamConnectDidTimeout:(XMPPStream *)sender{
    NSLog(@"%s__%d__",__FUNCTION__,__LINE__);
}
@end

登陸

  • 我們在登陸頁面點擊登陸按鈕的時候調(diào)用XMPPManager的-(void)loginWithUser:(NSString *)user password:(NSString *)password;進行登陸,但是我們在進行登陸的時候是需要服務(wù)器的驗證的所有這些都直接在代碼理顯示了,如下:
#import <Foundation/Foundation.h>
#import "XMPPFramework.h"

#import "LoginViewController.h"
#import "XMPPManager.h"
@interface LoginViewController ()<XMPPStreamDelegate>
@property (weak, nonatomic) IBOutlet UITextField *userName;
@property (weak, nonatomic) IBOutlet UITextField *userPassword;
@end

@implementation LoginViewController
- (IBAction)loginButton:(id)sender {
    //獲取用戶名和密碼
    NSString *userName = self.userName.text;
    NSString *userPassword = self.userPassword.text;
    
    [[XMPPManager sharedXMPPManager]loginWithUser:userName password:userPassword];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    [[XMPPManager sharedXMPPManager].stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
    // Do any additional setup after loading the view.
}

#pragma mark--XMPPStreamDelegate  進行身份驗證
//驗證成功
-(void)xmppStreamDidAuthenticate:(XMPPStream *)sender{
    
    NSLog(@"%s__%d__驗證成功",__FUNCTION__,__LINE__);
    
    [[NSUserDefaults standardUserDefaults]setObject:self.userName.text forKey:@"userName"];
    [[NSUserDefaults standardUserDefaults]setObject:self.userPassword.text forKey:@"userPassword"];
    [[NSUserDefaults standardUserDefaults]synchronize];//立即存儲
    
    [self dismissViewControllerAnimated:YES completion:nil];
}
//驗證失敗
-(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error{
    NSLog(@"%s__%d__驗證出錯:%@",__FUNCTION__,__LINE__,error);
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

@end
  • 此時我們也需要在AppDelegate里面作如下處理,當(dāng)我們再次打開應(yīng)用程序的時候要是已經(jīng)驗證成功就顯示好友列表頁面,否則的話就顯示登陸注冊頁面,由于清一色的代碼 給大家來張圖緩解一下緊張的氣氛吧。
此時的頁面
#import "AppDelegate.h"
@interface AppDelegate ()
@end
@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    if (nil == [[NSUserDefaults standardUserDefaults]objectForKey:@"userName"]) {
        UIStoryboard *story = [UIStoryboard storyboardWithName:@"LoginAndPregist" bundle:nil];
        UINavigationController *nv = [story instantiateInitialViewController];
        [self.window makeKeyAndVisible];
        [self.window.rootViewController presentViewController:nv animated:YES completion:^{
        }];
    }else{
        NSString *userName = [[NSUserDefaults standardUserDefaults]objectForKey:@"userName"];
        NSString *password = [[NSUserDefaults standardUserDefaults]objectForKey:@"userPassword"];
        [[XMPPManager sharedXMPPManager]loginWithUser:userName password:password];
        [[XMPPManager sharedXMPPManager].stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
    }
    return YES;
}
#pragma mark--XMPPStreamDelegate
//驗證成功
-(void)xmppStreamDidAuthenticate:(XMPPStream *)sender{
    NSLog(@"%s__%d__",__FUNCTION__,__LINE__);
    
    //我們驗證之后默認的狀態(tài)是離線的 于是我們想顯示在線,需要告訴服務(wù)器自己的狀態(tài)
    XMPPPresence *presence = [XMPPPresence presenceWithType:@"available"];
    [[XMPPManager sharedXMPPManager].stream sendElement:presence];
}
//驗證失敗
-(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error{
}

注冊

  • 其實注冊和登陸是有很大的相似性的,例如同樣需要遵守XMPPStreamDelegate協(xié)議,我們點擊注冊按鈕的時候是會執(zhí)行XMPPManager-(void)registWithUser:(NSString*)user password:(NSString *)password;進行注冊一樣的注冊成功還是失敗都會有相應(yīng)的方法來執(zhí)行,
#import "RegistViewController.h"
#import "XMPPManager.h"
@interface RegistViewController ()<XMPPStreamDelegate>
@property (weak, nonatomic) IBOutlet UITextField *userName;
@property (weak, nonatomic) IBOutlet UITextField *userPassword;

@end

@implementation RegistViewController

- (IBAction)registButton:(id)sender {
    NSString *userName =self.userName.text;
    NSString *userpassword = self.userPassword.text;
    [[XMPPManager sharedXMPPManager]registWithUser:userName password:userpassword];
}
- (void)viewDidLoad {
    [super viewDidLoad];
    
    //設(shè)置代理
    [[XMPPManager sharedXMPPManager].stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark--XMPPStreamDelegate
//注冊成功
-(void)xmppStreamDidRegister:(XMPPStream *)sender{
    NSLog(@"%s__%d__注冊成功",__FUNCTION__,__LINE__);
    
    //注冊成功之后返回到登陸界面
    [self.navigationController popToRootViewControllerAnimated:YES];
}
//注冊失敗
-(void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error{
    NSLog(@"%s__%d__注冊失敗%@",__FUNCTION__,__LINE__,error);
}
@end

獲取好友列表

  • 獲取還有列表我們需要在XMPPManager里面創(chuàng)建一個XMPPRoster對象
  • 這個對象具有添加好友 刪除好友 獲取好友列表等功能
@property(nonatomic,strong)XMPPRoster *xmppRoster;

具體的代碼部分 我寫的非常詳細 大家接著看

#import "RosterTableViewController.h"
#import "XMPPManager.h"
#import "ChatTableViewController.h"
@interface RosterTableViewController ()<XMPPRosterDelegate>
@property(nonatomic,strong)NSMutableArray *rosterArray;//保存獲取的好友
@end

@implementation RosterTableViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //初始化數(shù)組 這個數(shù)組里面保存的是獲取的好友
    self.rosterArray = [NSMutableArray arrayWithCapacity:10];
    
    [[XMPPManager sharedXMPPManager].xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.rosterArray.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
    XMPPJID *jid = self.rosterArray[indexPath.row];
    cell.textLabel.text = jid.user;
    return cell;
}

#pragma mark--XMPPRosterDelegate
//剛開始獲取好友列表
-(void)xmppRosterDidBeginPopulating:(XMPPRoster *)sender{
    NSLog(@"%s__%d__",__FUNCTION__,__LINE__);
}
//正在獲取好友列表
-(void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DDXMLElement *)item{
    NSLog(@"%s__%d__Item=%@",__FUNCTION__,__LINE__,item);
    NSString *jidStr = [[item attributeForName:@"jid"]stringValue];
    XMPPJID *jid =[XMPPJID jidWithString:jidStr];
    [self.rosterArray addObject:jid];
    
    //將數(shù)據(jù)添加進數(shù)組
    [self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:self.rosterArray.count-1 inSection:0]] withRowAnimation:UITableViewRowAnimationLeft];
}
//已經(jīng)完成獲取好友列表
-(void)xmppRosterDidEndPopulating:(XMPPRoster *)sender{
    NSLog(@"%s__%d__",__FUNCTION__,__LINE__);
}

#pragma mark--這個方法的作用是傳遞一個值到我們需要點擊進入的聊天頁面,同時在聊天頁面設(shè)置一個屬性值來接收
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    UITableViewCell *cell = (UITableViewCell *)sender;
    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
    XMPPJID *jid = self.rosterArray[indexPath.row];
    ChatTableViewController *chat = segue.destinationViewController;
    chat.chatToJid = jid;
}
@end

聊天頁面

  • 我們在聊天頁面開了一個接口,來接受列表頁面?zhèn)鬟M來的XMPPJID
#import <UIKit/UIKit.h>
#import "XMPPManager.h"
@interface ChatTableViewController : UITableViewController
@property(nonatomic,strong)XMPPJID *chatToJid;//要聊天的好友
@end
  • 首先,在ChatTableViewController.m里面 我們同樣的遵守代理協(xié)議XMPPStreamDelegate,定義一個可變數(shù)組來接收查詢的所有聊天信息
@implementation ChatTableViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.allMessageArray = [NSMutableArray array];//初始化數(shù)組
    
    [[XMPPManager sharedXMPPManager].stream addDelegate:self delegateQueue:dispatch_get_main_queue()];//設(shè)置監(jiān)測對象
    [self reloadMessage];
}
//點擊右上角添加按鈕傳遞一條信息
- (IBAction)addButton:(id)sender {
    XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:self.chatToJid];
    [message addBody:@"Hello"];
    [[XMPPManager sharedXMPPManager].stream sendElement:message];
}
  • 以下是XMPPStreamDelegate對于信息發(fā)送的幾個方法
#pragma mark--XMPPStreamDelegate
//發(fā)送信息成功
-(void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message{
    NSLog(@"%s__%d__",__FUNCTION__,__LINE__);
    [self reloadMessage];//發(fā)送信息是 刷新一次頁面
}
//發(fā)送信息失敗
-(void)xmppStream:(XMPPStream *)sender didFailToSendMessage:(XMPPMessage *)message error:(NSError *)error{
    NSLog(@"%s__%d__Error:%@",__FUNCTION__,__LINE__,error);
}
//收到信息
-(void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message{
    NSLog(@"%s__%d__Message=%@",__FUNCTION__,__LINE__,message);
    [self reloadMessage];//收到信息是刷新一次頁面
}
  • 我們在發(fā)送消失 或者接收到消失 以及我們進入頁面的時候都會顯示相應(yīng)的內(nèi)容 這其實就設(shè)計頁面數(shù)據(jù)加載的內(nèi)容,因此我們自定義一個方法,用來加載聊天頁面的內(nèi)容,并在相應(yīng)的方法里進行調(diào)用
#pragma mark--加載聊天信息
-(void)reloadMessage{
    
    NSManagedObjectContext *managerObjectContext =[XMPPManager sharedXMPPManager].messageManagerContext;
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPMessageArchiving_Message_CoreDataObject" inManagedObjectContext:managerObjectContext];
    [fetchRequest setEntity:entity];
    // Specify criteria for filtering which objects to fetch
    
    //我們要是不設(shè)置相應(yīng)的檢索條件的話 就會吧所有的聊天信息檢索出來出來
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"bareJidStr == %@ And streamBareJidStr == %@", self.chatToJid.bare,[XMPPManager sharedXMPPManager].stream.myJID.bare];//對方的Jid和自己的Jid
    [fetchRequest setPredicate:predicate];
    //以上查詢出來的結(jié)果就是當(dāng)前用戶和聊天用戶之間的信息
    // Specify how the fetched objects should be sorted
    //設(shè)置
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timestamp" ascending:YES];
    [fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]];
    
    NSError *error = nil;
    NSArray *fetchedObjects = [managerObjectContext executeFetchRequest:fetchRequest error:&error];
    if (fetchedObjects == nil) {
        NSLog(@"沒有檢索出任何內(nèi)容");
    }else{
        
        //在此判斷一下,因為日要是點擊一個人,沒有聊天記錄的話直接return 否則會崩掉的
        if (fetchedObjects.count == 0) {
            return;
        }
        [self.allMessageArray removeAllObjects];
        [self.allMessageArray addObjectsFromArray:fetchedObjects];
        [self.tableView reloadData];
        
        //進行信息加載的時候讓tableView 滾動到最底部
        [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:self.allMessageArray.count-1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
    }
}
  • 至于UITableView data source的幾個代理方法就簡單的不行不行的了。。。Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    
    return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    
    return self.allMessageArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Message" forIndexPath:indexPath];
    
    XMPPMessageArchiving_Message_CoreDataObject *message = self.allMessageArray[indexPath.row];
    
    //判斷聊天信息是發(fā)出去的 還是接受進來的,在cell上顯示不一樣的樣式
    if (message.isOutgoing == YES) {
        cell.detailTextLabel.text = message.body;
        cell.textLabel.text = @"";
    }else{
        cell.textLabel.text = message.body;
        cell.detailTextLabel.text = @"";
    }
    return cell;
}
  • 以上就是XMPP實現(xiàn)聊天功能的基本內(nèi)容,我們在以代碼為伍的時候 可以用Openfile和spark等工具幫助我們進行調(diào)試~~~~~
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,990評論 2 374

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