微信,QQ這類IM app怎么做——談?wù)刉ebsocket

前言

關(guān)于我和WebSocket的緣:我從大二在計(jì)算機(jī)網(wǎng)絡(luò)課上聽(tīng)老師講過(guò)之后,第一次使用就到了畢業(yè)之后的第一份工作。直到最近換了工作,到了一家是含有IM社交聊天功能的app的時(shí)候昆箕,我覺(jué)得我現(xiàn)在可以談?wù)勎覍?duì)WebSocket/Socket的一些看法了。要想做IM聊天app租冠,就不得不理解WebSocket和Socket的原理了鹏倘,聽(tīng)我一一道來(lái)。

目錄

  • 1.WebSocket使用場(chǎng)景
  • 2.WebSocket誕生由來(lái)
  • 3.談?wù)刉ebSocket協(xié)議原理
  • 4.WebSocket 和 Socket的區(qū)別與聯(lián)系
  • 5.iOS平臺(tái)有哪些WebSocket和Socket的開源框架
  • 6.iOS平臺(tái)如何實(shí)現(xiàn)WebSocket協(xié)議
一.WebSocket的使用場(chǎng)景

1.社交聊天
最著名的就是微信肺稀,QQ第股,這一類社交聊天的app应民。這一類聊天app的特點(diǎn)是低延遲话原,高即時(shí)。即時(shí)是這里面要求最高的诲锹,如果有一個(gè)緊急的事情繁仁,通過(guò)IM軟件通知你,假設(shè)網(wǎng)絡(luò)環(huán)境良好的情況下归园,這條message還無(wú)法立即送達(dá)到你的客戶端上黄虱,緊急的事情都結(jié)束了,你才收到消息庸诱,那么這個(gè)軟件肯定是失敗的捻浦。
2.彈幕
說(shuō)到這里,大家一定里面想到了A站和B站了桥爽。確實(shí)朱灿,他們的彈幕一直是一種特色。而且彈幕對(duì)于一個(gè)視頻來(lái)說(shuō)钠四,很可能彈幕才是精華盗扒。發(fā)彈幕需要實(shí)時(shí)顯示,也需要和聊天一樣,需要即時(shí)侣灶。
3.多玩家游戲
4.協(xié)同編輯
現(xiàn)在很多開源項(xiàng)目都是分散在世界各地的開發(fā)者一起協(xié)同開發(fā)甸祭,此時(shí)就會(huì)用到版本控制系統(tǒng),比如Git褥影,SVN去合并沖突池户。但是如果有一份文檔,支持多人實(shí)時(shí)在線協(xié)同編輯伪阶,那么此時(shí)就會(huì)用到比如WebSocket了煞檩,它可以保證各個(gè)編輯者都在編輯同一個(gè)文檔,此時(shí)不需要用到Git栅贴,SVN這些版本控制斟湃,因?yàn)樵趨f(xié)同編輯界面就會(huì)實(shí)時(shí)看到對(duì)方編輯了什么,誰(shuí)在修改哪些段落和文字檐薯。
5.股票基金實(shí)時(shí)報(bào)價(jià)
金融界瞬息萬(wàn)變——幾乎是每毫秒都在變化凝赛。如果采用的網(wǎng)絡(luò)架構(gòu)無(wú)法滿足實(shí)時(shí)性,那么就會(huì)給客戶帶來(lái)巨大的損失坛缕。幾毫秒錢股票開始大跌墓猎,幾秒以后才刷新數(shù)據(jù),一秒鐘的時(shí)間內(nèi)赚楚,很可能用戶就已經(jīng)損失巨大財(cái)產(chǎn)了毙沾。
6.體育實(shí)況更新
全世界的球迷,體育愛(ài)好者特別多宠页,當(dāng)然大家在關(guān)心自己喜歡的體育活動(dòng)的時(shí)候左胞,比賽實(shí)時(shí)的賽況是他們最最關(guān)心的事情。這類新聞中最好的體驗(yàn)就是利用Websocket達(dá)到實(shí)時(shí)的更新举户!
7.視頻會(huì)議/聊天
視頻會(huì)議并不能代替和真人相見(jiàn)烤宙,但是他能讓分布在全球天涯海角的人聚在電腦前一起開會(huì)。既能節(jié)省大家聚在一起路上花費(fèi)的時(shí)間俭嘁,討論聚會(huì)地點(diǎn)的糾結(jié)躺枕,還能隨時(shí)隨地,只要有網(wǎng)絡(luò)就可以開會(huì)供填。
8.基于位置的應(yīng)用
越來(lái)越多的開發(fā)者借用移動(dòng)設(shè)備的GPS功能來(lái)實(shí)現(xiàn)他們基于位置的網(wǎng)絡(luò)應(yīng)用拐云。如果你一直記錄用戶的位置(比如運(yùn)行應(yīng)用來(lái)記錄運(yùn)動(dòng)軌跡),你可以收集到更加細(xì)致化的數(shù)據(jù)近她。
9.在線教育
在線教育近幾年也發(fā)展迅速叉瘩。優(yōu)點(diǎn)很多,免去了場(chǎng)地的限制泄私,能讓名師的資源合理的分配給全國(guó)各地想要學(xué)習(xí)知識(shí)的同學(xué)手上房揭,Websocket是個(gè)不錯(cuò)的選擇备闲,可以視頻聊天、即時(shí)聊天以及其與別人合作一起在網(wǎng)上討論問(wèn)題...
10.智能家居
這也是我一畢業(yè)加入的一個(gè)偉大的物聯(lián)網(wǎng)智能家居的公司捅暴√裆埃考慮到家里的智能設(shè)備的狀態(tài)必須需要實(shí)時(shí)的展現(xiàn)在手機(jī)app客戶端上,毫無(wú)疑問(wèn)選擇了Websocket蓬痒。
11.總結(jié)
從上面我列舉的這些場(chǎng)景來(lái)看泻骤,一個(gè)共同點(diǎn)就是,高實(shí)時(shí)性梧奢!

二.WebSocket誕生由來(lái)

1.最開始的輪詢Polling階段

這種方式下狱掂,是不適合獲取實(shí)時(shí)信息的,客戶端和服務(wù)器之間會(huì)一直進(jìn)行連接亲轨,每隔一段時(shí)間就詢問(wèn)一次趋惨。客戶端會(huì)輪詢惦蚊,有沒(méi)有新消息器虾。這種方式連接數(shù)會(huì)很多,一個(gè)接受蹦锋,一個(gè)發(fā)送兆沙。而且每次發(fā)送請(qǐng)求都會(huì)有Http的Header,會(huì)很耗流量莉掂,也會(huì)消耗CPU的利用率葛圃。

2.改進(jìn)版的長(zhǎng)輪詢Long polling階段

長(zhǎng)輪詢是對(duì)輪詢的改進(jìn)版,客戶端發(fā)送HTTP給服務(wù)器之后憎妙,有沒(méi)有新消息库正,如果沒(méi)有新消息,就一直等待尚氛。當(dāng)有新消息的時(shí)候诀诊,才會(huì)返回給客戶端洞渤。在某種程度上減小了網(wǎng)絡(luò)帶寬和CPU利用率等問(wèn)題阅嘶。但是這種方式還是有一種弊端:例如假設(shè)服務(wù)器端的數(shù)據(jù)更新速度很快,服務(wù)器在傳送一個(gè)數(shù)據(jù)包給客戶端后必須等待客戶端的下一個(gè)Get請(qǐng)求到來(lái)载迄,才能傳遞第二個(gè)更新的數(shù)據(jù)包給客戶端讯柔,那么這樣的話,客戶端顯示實(shí)時(shí)數(shù)據(jù)最快的時(shí)間為2×RTT(往返時(shí)間)护昧,而且如果在網(wǎng)絡(luò)擁塞的情況下魂迄,這個(gè)時(shí)間用戶是不能接受的,比如在股市的的報(bào)價(jià)上惋耙。另外捣炬,由于http數(shù)據(jù)包的頭部數(shù)據(jù)量往往很大(通常有400多個(gè)字節(jié))熊昌,但是真正被服務(wù)器需要的數(shù)據(jù)卻很少(有時(shí)只有10個(gè)字節(jié)左右),這樣的數(shù)據(jù)包在網(wǎng)絡(luò)上周期性的傳輸湿酸,難免對(duì)網(wǎng)絡(luò)帶寬是一種浪費(fèi)婿屹。

3.WebSocket誕生

現(xiàn)在急需的需求是能支持客戶端和服務(wù)器端的雙向通信,而且協(xié)議的頭部又沒(méi)有HTTP的Header那么大推溃,于是昂利,Websocket就誕生了!

上圖就是Websocket和Polling的區(qū)別铁坎,從圖中可以看到Polling里面客戶端發(fā)送了好多Request蜂奸,而下圖,只有一個(gè)Upgrade硬萍,非常簡(jiǎn)潔高效扩所。至于消耗方面的比較就要看下圖了


上圖中,我們先看藍(lán)色的柱狀圖朴乖,是Polling輪詢消耗的流量碌奉,這次測(cè)試,HTTP請(qǐng)求和響應(yīng)頭信息開銷總共包括871字節(jié)寒砖。當(dāng)然每次測(cè)試不同的請(qǐng)求赐劣,頭的開銷不同。這次測(cè)試都以871字節(jié)的請(qǐng)求來(lái)測(cè)試哩都。
**Use case A: **1,000 clients polling every second: Network throughput is (871 x 1,000) = 871,000 bytes = 6,968,000 bits per second (6.6 Mbps)
**Use case B: **10,000 clients polling every second: Network throughput is (871 x 10,000) = 8,710,000 bytes = 69,680,000 bits per second (66 Mbps)
**Use case C: **100,000 clients polling every 1 second: Network throughput is (871 x 100,000) = 87,100,000 bytes = 696,800,000 bits per second (665 Mbps)
而Websocket的Frame是 just two bytes of overhead instead of 871魁兼,僅僅用2個(gè)字節(jié)就代替了輪詢的871字節(jié)!
**Use case A: **1,000 clients receive 1 message per second: Network throughput is (2 x 1,000) = 2,000 bytes = 16,000 bits per second (0.015 Mbps)
**Use case B: **10,000 clients receive 1 message per second: Network throughput is (2 x 10,000) = 20,000 bytes = 160,000 bits per second (0.153 Mbps)
**Use case C: **100,000 clients receive 1 message per second: Network throughput is (2 x 100,000) = 200,000 bytes = 1,600,000 bits per second (1.526 Mbps)

相同的每秒客戶端輪詢的次數(shù)漠嵌,當(dāng)次數(shù)高達(dá)10W/s的高頻率次數(shù)的時(shí)候咐汞,Polling輪詢需要消耗665Mbps,而Websocket僅僅只花費(fèi)了1.526Mbps儒鹿,將近435倍;骸!

三.談?wù)刉ebSocket協(xié)議原理

Websocket是應(yīng)用層第七層上的一個(gè)應(yīng)用層協(xié)議约炎,它必須依賴 HTTP 協(xié)議進(jìn)行一次握手 植阴,握手成功后,數(shù)據(jù)就直接從 TCP 通道傳輸圾浅,與 HTTP 無(wú)關(guān)了掠手。

Websocket的數(shù)據(jù)傳輸是frame形式傳輸?shù)模热鐣?huì)將一條消息分為幾個(gè)frame狸捕,按照先后順序傳輸出去喷鸽。這樣做會(huì)有幾個(gè)好處:

1 大數(shù)據(jù)的傳輸可以分片傳輸,不用考慮到數(shù)據(jù)大小導(dǎo)致的長(zhǎng)度標(biāo)志位不足夠的情況灸拍。
2 和http的chunk一樣做祝,可以邊生成數(shù)據(jù)邊傳遞消息砾省,即提高傳輸效率。

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-------+-+-------------+-------------------------------+
 |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
 |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
 |N|V|V|V|       |S|             |   (if payload len==126/127)   |
 | |1|2|3|       |K|             |                               |
 +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
 |     Extended payload length continued, if payload len == 127  |
 + - - - - - - - - - - - - - - - +-------------------------------+
 |                               |Masking-key, if MASK set to 1  |
 +-------------------------------+-------------------------------+
 | Masking-key (continued)       |          Payload Data         |
 +-------------------------------- - - - - - - - - - - - - - - - +
 :                     Payload Data continued ...                :
 + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
 |                     Payload Data continued ...                |
 +---------------------------------------------------------------+



    FIN      1bit 表示信息的最后一幀混槐,flag纯蛾,也就是標(biāo)記符
    RSV 1-3  1bit each 以后備用的 默認(rèn)都為 0
    Opcode   4bit 幀類型,稍后細(xì)說(shuō)
    Mask     1bit 掩碼纵隔,是否加密數(shù)據(jù)翻诉,默認(rèn)必須置為1 (這里很蛋疼)
    Payload  7bit 數(shù)據(jù)的長(zhǎng)度
    Masking-key      1 or 4 bit 掩碼
    Payload data     (x + y) bytes 數(shù)據(jù)
    Extension data   x bytes  擴(kuò)展數(shù)據(jù)
    Application data y bytes  程序數(shù)據(jù)

具體的規(guī)范,還請(qǐng)看官網(wǎng)的RFC 6455文檔給出的詳細(xì)定義捌刮。這里還有一個(gè)翻譯版本

四.WebSocket 和 Socket的區(qū)別與聯(lián)系

首先碰煌,
Socket 其實(shí)并不是一個(gè)協(xié)議。它工作在 OSI 模型會(huì)話層(第5層)绅作,是為了方便大家直接使用更底層協(xié)議(一般是 TCPUDP )而存在的一個(gè)抽象層芦圾。Socket是對(duì)TCP/IP協(xié)議的封裝,Socket本身并不是協(xié)議俄认,而是一個(gè)調(diào)用接口(API)个少。


Socket通常也稱作”套接字”,用于描述IP地址和端口眯杏,是一個(gè)通信鏈的句柄夜焦。網(wǎng)絡(luò)上的兩個(gè)程序通過(guò)一個(gè)雙向的通訊連接實(shí)現(xiàn)數(shù)據(jù)的交換,這個(gè)雙向鏈路的一端稱為一個(gè)Socket岂贩,一個(gè)Socket由一個(gè)IP地址和一個(gè)端口號(hào)唯一確定茫经。應(yīng)用程序通常通過(guò)”套接字”向網(wǎng)絡(luò)發(fā)出請(qǐng)求或者應(yīng)答網(wǎng)絡(luò)請(qǐng)求。

Socket在通訊過(guò)程中萎津,服務(wù)端監(jiān)聽(tīng)某個(gè)端口是否有連接請(qǐng)求卸伞,客戶端向服務(wù)端發(fā)送連接請(qǐng)求,服務(wù)端收到連接請(qǐng)求向客戶端發(fā)出接收消息锉屈,這樣一個(gè)連接就建立起來(lái)了荤傲。客戶端和服務(wù)端也都可以相互發(fā)送消息與對(duì)方進(jìn)行通訊颈渊,直到雙方連接斷開遂黍。

所以基于WebSocket和基于Socket都可以開發(fā)出IM社交聊天類的app

五.iOS平臺(tái)有哪些WebSocket和Socket的開源框架

Socket開源框架有:CocoaAsyncSocketsocketio/socket.io-client-swift
WebSocket開源框架有:facebook/SocketRocket儡炼,tidwall/SwiftWebSocket

六.iOS平臺(tái)如何實(shí)現(xiàn)WebSocket協(xié)議

Talk is cheap妓湘。Show me the code ——Linus Torvalds

我們今天來(lái)看看facebook/SocketRocket的實(shí)現(xiàn)方法
首先這是SRWebSocket定義的一些成員變量


@property (nonatomic, weak) id <SRWebSocketDelegate> delegate;
/**
 A dispatch queue for scheduling the delegate calls. The queue doesn't need be a serial queue.

 If `nil` and `delegateOperationQueue` is `nil`, the socket uses main queue for performing all delegate method calls.
 */
@property (nonatomic, strong) dispatch_queue_t delegateDispatchQueue;
/**
 An operation queue for scheduling the delegate calls.

 If `nil` and `delegateOperationQueue` is `nil`, the socket uses main queue for performing all delegate method calls.
 */
@property (nonatomic, strong) NSOperationQueue *delegateOperationQueue;
@property (nonatomic, readonly) SRReadyState readyState;
@property (nonatomic, readonly, retain) NSURL *url;
@property (nonatomic, readonly) CFHTTPMessageRef receivedHTTPHeaders;
// Optional array of cookies (NSHTTPCookie objects) to apply to the connections
@property (nonatomic, copy) NSArray<NSHTTPCookie *> *requestCookies;

// This returns the negotiated protocol.
// It will be nil until after the handshake completes.
@property (nonatomic, readonly, copy) NSString *protocol;

下面這些是SRWebSocket的一些方法


// Protocols should be an array of strings that turn into Sec-WebSocket-Protocol.
- (instancetype)initWithURLRequest:(NSURLRequest *)request;
- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray<NSString *> *)protocols;
- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray<NSString *> *)protocols allowsUntrustedSSLCertificates:(BOOL)allowsUntrustedSSLCertificates;

// Some helper constructors.
- (instancetype)initWithURL:(NSURL *)url;
- (instancetype)initWithURL:(NSURL *)url protocols:(NSArray<NSString *> *)protocols;
- (instancetype)initWithURL:(NSURL *)url protocols:(NSArray<NSString *> *)protocols allowsUntrustedSSLCertificates:(BOOL)allowsUntrustedSSLCertificates;

// By default, it will schedule itself on +[NSRunLoop SR_networkRunLoop] using defaultModes.
- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;
- (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;

// SRWebSockets are intended for one-time-use only.  Open should be called once and only once.
- (void)open;
- (void)close;
- (void)closeWithCode:(NSInteger)code reason:(NSString *)reason;

///--------------------------------------
#pragma mark Send
///--------------------------------------

//下面是4個(gè)發(fā)送的方法
/**
 Send a UTF-8 string or binary data to the server.

 @param message UTF-8 String or Data to send.

 @deprecated Please use `sendString:` or `sendData` instead.
 */
- (void)send:(id)message __attribute__((deprecated("Please use `sendString:` or `sendData` instead.")));
- (void)sendString:(NSString *)string;
- (void)sendData:(NSData *)data;
- (void)sendPing:(NSData *)data;

@end

對(duì)應(yīng)5種狀態(tài)的代理方法

///--------------------------------------
#pragma mark - SRWebSocketDelegate
///--------------------------------------
@protocol SRWebSocketDelegate <NSObject>

- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;

@optional
- (void)webSocketDidOpen:(SRWebSocket *)webSocket;
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean;
- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload;

// Return YES to convert messages sent as Text to an NSString. Return NO to skip NSData -> NSString conversion for Text messages. Defaults to YES.
- (BOOL)webSocketShouldConvertTextFrameToString:(SRWebSocket *)webSocket;
@end

didReceiveMessage方法是必須實(shí)現(xiàn)的查蓉,用來(lái)接收消息的乌询。
下面4個(gè)did方法分別對(duì)應(yīng)著Open,F(xiàn)ail豌研,Close妹田,ReceivePong不同狀態(tài)的代理方法

方法就上面這些了唬党,我們實(shí)際來(lái)看看代碼怎么寫

先是初始化Websocket連接,注意此處ws://或者wss://連接有且最多只能有一個(gè)鬼佣,這個(gè)是Websocket協(xié)議規(guī)定的

    self.ws = [[SRWebSocket alloc] initWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@://%@:%zd/ws", serverProto, serverIP, serverPort]]]];
    self.ws.delegate = delegate;
    [self.ws open];

發(fā)送消息

    [self.ws send:message];

接收消息以及其他3個(gè)代理方法

//這個(gè)就是接受消息的代理方法了驶拱,這里接受服務(wù)器返回的數(shù)據(jù),方法里面就應(yīng)該寫處理數(shù)據(jù)晶衷,存儲(chǔ)數(shù)據(jù)的方法了蓝纲。
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message
{
    NSDictionary *data = [NetworkUtils decodeData:message];
    if (!data)
        return;
}

//這里是Websocket剛剛Open之后的代理方法。就想微信剛剛連接中晌纫,會(huì)顯示連接中税迷,當(dāng)連接上了,就不顯示連接中了锹漱,取消顯示連接的方法就應(yīng)該寫在這里面
- (void)webSocketDidOpen:(SRWebSocket *)webSocket
{
    // Open = silent ping
    [self.ws receivedPing];
}

//這是關(guān)閉Websocket的代理方法
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean
{
    [self failedConnection:NSLS(Disconnected)];
}

//這里是連接Websocket失敗的方法箭养,這里面一般都會(huì)寫重連的方法
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error
{
    [self failedConnection:NSLS(Disconnected)];
}

最后

以上就是我想分享的一些關(guān)于Websocket的心得,文中如果有錯(cuò)誤的地方哥牍,歡迎大家指點(diǎn)毕泌!一般沒(méi)有微信QQ那么大用戶量的app,用Websocket應(yīng)該都可以完成IM社交聊天的任務(wù)嗅辣。當(dāng)用戶達(dá)到億級(jí)別撼泛,應(yīng)該還有很多需要優(yōu)化,優(yōu)化性能各種的吧澡谭。

最后坎弯,微信和QQ的實(shí)現(xiàn)方法也許并不是只用Websocket和Socket這么簡(jiǎn)單,也許是他們自己開發(fā)的一套能支持這么大用戶译暂,大數(shù)據(jù)的抠忘,各方面也都優(yōu)化都最優(yōu)的方法。如果有開發(fā)和微信和QQ的大神看到這篇文章外永,可以留言說(shuō)說(shuō)看你們用什么方式實(shí)現(xiàn)的崎脉,也可以和我們一起分享,我們一起學(xué)習(xí)伯顶!我先謝謝大神們的指點(diǎn)了囚灼!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市祭衩,隨后出現(xiàn)的幾起案子灶体,更是在濱河造成了極大的恐慌,老刑警劉巖掐暮,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蝎抽,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡路克,警方通過(guò)查閱死者的電腦和手機(jī)樟结,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門养交,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人瓢宦,你說(shuō)我怎么就攤上這事碎连。” “怎么了驮履?”我有些...
    開封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵鱼辙,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我玫镐,道長(zhǎng)座每,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任摘悴,我火速辦了婚禮峭梳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蹂喻。我一直安慰自己葱椭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開白布口四。 她就那樣靜靜地躺著孵运,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蔓彩。 梳的紋絲不亂的頭發(fā)上治笨,一...
    開封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音赤嚼,去河邊找鬼旷赖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛更卒,可吹牛的內(nèi)容都是我干的等孵。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼蹂空,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼俯萌!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起上枕,我...
    開封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤咐熙,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后辨萍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體棋恼,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蘸泻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片琉苇。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嘲玫,死狀恐怖悦施,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情去团,我是刑警寧澤抡诞,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站土陪,受9級(jí)特大地震影響昼汗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鬼雀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一顷窒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧源哩,春花似錦鞋吉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)京景。三九已至喻鳄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間顶考,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留舷蒲,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓友多,卻偏偏與公主長(zhǎng)得像阿纤,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子夷陋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

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

  • 今天我將為大家介紹常用的幾種消息推送:JMS,MQTT,XMPP,WebSocket,AMQP,友盟欠拾,環(huán)信。 首先...
    馬小悅閱讀 2,114評(píng)論 0 7
  • 初涉IM骗绕,首先我有這么幾個(gè)問(wèn)題需要弄明白: Socket 和 WebSocket 有哪些區(qū)別和聯(lián)系藐窄? WebSoc...
    夜幕青雨閱讀 11,133評(píng)論 8 39
  • WebSocket簡(jiǎn)介 談到Web實(shí)時(shí)推送,就不得不說(shuō)WebSocket酬土。在WebSocket出現(xiàn)之前荆忍,很多網(wǎng)站為...
    吧啦啦小湯圓閱讀 8,148評(píng)論 15 75
  • 石堅(jiān)聽(tīng)到老伴的埋汰,心里清楚她是在激將自己。 但他自己也知道刹枉,現(xiàn)在這個(gè)模樣的自己叽唱,確實(shí)像丟了魂似的,他需要改變微宝。 ...
    魚團(tuán)子環(huán)游銀河鐵道閱讀 267評(píng)論 0 0
  • 我家的“二胎”是一只普通短毛貓棺亭,屬龍,雙子座蟋软,大名果果镶摘。 它一個(gè)多月大的時(shí)候被抱回了家,從此岳守,我家有了“二胎”凄敢,果...
    一口一閱讀 813評(píng)論 2 4