Android-IpReachabilityMonitor


簡介

本文主要介紹基于Android 7.0 的IpReachabilityMonitor機(jī)制


IpReachabilityMonitor簡介

* Monitors on-link IP reachability and notifies callers whenever any on-link addresses of interest appear to have become unresponsive.

//監(jiān)視鏈路IP的可達(dá)性旺拉;無論任何時(shí)候羡玛,一旦所關(guān)注的鏈路地址變的不響應(yīng)時(shí)垮衷,就會(huì)通知調(diào)用者杰赛。

This code does not concern itself with "why" a neighbour might have become unreachable. Instead, it primarily reacts to the kernel's notion of IP reachability for each of the neighbours we know to be critically important to normal network connectivity. As such, it is often "just the messenger":the neighbours about which it warns are already deemed by the kernel to have become unreachable.

//IpReachabilityMonitor的代碼實(shí)現(xiàn)邏輯不關(guān)心為什么一個(gè)neighbour網(wǎng)絡(luò)變?yōu)椴豢蛇_(dá)。相反兽泄,他主要反映在內(nèi)核層面中每一個(gè)neighbour網(wǎng)絡(luò)的IP可達(dá)性概念或狀態(tài)漓概。我們知道這個(gè)IP可達(dá)性狀態(tài)對(duì)于正常網(wǎng)絡(luò)連接來說是關(guān)鍵重要的。因此病梢,IpReachabilityMonitor通常僅是“信使”:它警告neighbours網(wǎng)絡(luò)已經(jīng)被內(nèi)核kernel視為不可達(dá)胃珍。


IpReachabilityMonitor工作方式

How it works:

1. The "on-link neighbours of interest" found in a given LinkProperties instance are added to a "watch list" via #updateLinkProperties().This usually means all default gateways and any on-link DNS servers.

//1、在給定的LinkProperties實(shí)例中找到關(guān)注的鏈路neighbours網(wǎng)絡(luò)蜓陌,這些neighbours網(wǎng)絡(luò)被通過updateLinkProperties()方法添加到一個(gè)"watch list"中觅彰。這通常意味著所有默認(rèn)網(wǎng)關(guān)和鏈路DNS服務(wù)器。

2. We listen continuously for netlink neighbour messages (RTM_NEWNEIGH,RTM_DELNEIGH), watching only for neighbours in the watch list.

//2钮热、我們連續(xù)不斷地監(jiān)聽netlink消息(RTM_NEWNEIGH,RTM_DELNEIGH)填抬,僅僅關(guān)注在watch list中的neighbours網(wǎng)絡(luò)。

- A neighbour going into NUD_REACHABLE, NUD_STALE, NUD_DELAY, and even NUD_PROBE is perfectly normal; we merely record the new state.

//一個(gè)neighbour網(wǎng)絡(luò)進(jìn)入NUD_REACHABLE, NUD_STALE, NUD_DELAY和NUD_PROBE狀態(tài)隧期,均是完全正吵兆啵現(xiàn)象,我們只是記錄最新的狀態(tài)厌秒。

- A neighbour's entry may be deleted (RTM_DELNEIGH), for example due to garbage collection.? This is not necessarily of immediate concern; we record the neighbour as moving to NUD_NONE.

//一個(gè)neighbour條目可能被刪除(RTM_DELNEIGH)读拆,例如由于垃圾回收。這個(gè)沒有必要進(jìn)行立即關(guān)聯(lián)鸵闪。我們記錄被搬移到NUD_NONE狀態(tài)的neighbour網(wǎng)絡(luò)檐晕。

- A neighbour transitioning to NUD_FAILED (for any reason) is? critically important and is handled as described below in #4.

//一個(gè)neighbour網(wǎng)絡(luò)被轉(zhuǎn)移到NUD_FAILED(任何原因)是極其重要的,這個(gè)相應(yīng)的操作將會(huì)在下面#4描述蚌讼。

3. All on-link neighbours in the watch list can be forcibly "probed" by calling #probeAll(). This should be called whenever it is important to verify that critical neighbours on the link are still reachable, e.g. when roaming between BSSIDs.

//3辟灰、可以通過調(diào)用probeAll()方法來強(qiáng)制執(zhí)行probed所有在watch list 中的鏈路neighbours網(wǎng)絡(luò)。不管什么時(shí)候篡石,對(duì)于想驗(yàn)證鏈路上關(guān)鍵neighbour網(wǎng)絡(luò)依然可達(dá)芥喇,這個(gè)方法是重要的,應(yīng)該被調(diào)用凰萨,比如當(dāng)在不同的BSSID之間Roaming的時(shí)候继控。

- The kernel will send unicast ARP requests for IPv4 neighbours and unicast NS packets for IPv6 neighbours.? The expected replies will likely be unicast.

//內(nèi)核kernel將為IPv4 neighbour 網(wǎng)絡(luò)發(fā)送單播ARP請(qǐng)求和為IPv6 neighbour網(wǎng)絡(luò)發(fā)送單播NS數(shù)據(jù)包械馆。預(yù)期的答復(fù)可能是單播。

- The forced probing is done holding a wakelock. The kernel may,however, initiate probing of a neighbor on its own, i.e. whenever a neighbour has expired from NUD_DELAY.

//強(qiáng)制probing 必須持有一個(gè)wakelock才可以執(zhí)行武通。然而霹崎,內(nèi)核kernel也許引發(fā)自己的一個(gè)neighbor
網(wǎng)絡(luò)的probing,比如一個(gè)neighbour網(wǎng)絡(luò)已經(jīng)過期了(在進(jìn)入NUD_DELAY狀態(tài)后過期)冶忱。

- The kernel sends:

&1(/proc/sys/net/ipv{4,6}/neigh//ucast_solicit) number of probes (usually 3) every? ? ? ? &2(/proc/sys/net/ipv{4,6}/neigh//retrans_time_ms)number of milliseconds (usually 1000ms).

This normally results in 3 unicast packets, 1 per second.

//內(nèi)核Kernel每&2秒發(fā)送&1次Probe 單播請(qǐng)求尾菇。通常結(jié)果是每1秒發(fā)送3次單播請(qǐng)求。

- If no response is received to any of the probe packets, the kernel marks the neighbour as being in state NUD_FAILED, and the listening process in #2 will learn of it.

//如果對(duì)于所有的Probe 請(qǐng)求囚枪,都沒有接受到響應(yīng)派诬,內(nèi)核kernel會(huì)將neighbour網(wǎng)絡(luò)標(biāo)記為NUD_FAILED狀態(tài),在#2中描述的監(jiān)聽進(jìn)程將會(huì)學(xué)習(xí)它链沼。

4. We call the supplied Callback#notifyLost() function if the loss of a neighbour in NUD_FAILED would cause IPv4 or IPv6 configuration to become incomplete (a loss of provisioning).

//4千埃、如果處于NUD_FAILED狀態(tài)的neighbour網(wǎng)絡(luò)的丟失將會(huì)導(dǎo)致Ipv4 或者Ipv6配置變得不完整(配置丟失),我們將會(huì)調(diào)用提供的Callback#notifyLost()函數(shù)忆植。

- For example, losing all our IPv4 on-link DNS servers (or losing our only IPv6 default gateway) constitutes a loss of IPv4 (IPv6) provisioning; Callback#notifyLost() would be called.

//比如丟失所有IPv4鏈路DNS服務(wù)器(或者丟失僅有的Ipv6默認(rèn)網(wǎng)關(guān))會(huì)構(gòu)成Ipv4(Ipv6)配置丟失放可。

Callback#notifyLost()函數(shù)將會(huì)被調(diào)用。

- Since it can be non-trivial to reacquire certain IP provisioning state it may be best for the link to disconnect completely and reconnect afresh.

//因?yàn)橹匦芦@取特定的IP配置狀態(tài)是非常重要的朝刊。最好的方式是完全斷開連接耀里,然后進(jìn)行重連。


IpReachabilityMonitor實(shí)現(xiàn)

1拾氓、在給定的LinkProperties實(shí)例中找到關(guān)注的鏈路neighbours網(wǎng)絡(luò)冯挎,這些neighbours網(wǎng)絡(luò)被通過updateLinkProperties()方法添加到一個(gè)"watch list"中。這通常意味著所有默認(rèn)網(wǎng)關(guān)和鏈路DNS服務(wù)器咙鞍。

public void updateLinkProperties(LinkProperties lp)

? ? ? mLinkProperties = new LinkProperties(lp);? ? ? ? ? ?

???? MapnewIpWatchList = new HashMap<>();? ? ? ? ? ?

???? final Listroutes = mLinkProperties.getRoutes();

? //將處于鏈接狀態(tài)的默認(rèn)網(wǎng)關(guān)加入IpWatchList

??? for (RouteInfo route : routes) {

??????????? if (route.hasGateway()) {

?????????????????????? InetAddress gw = route.getGateway();

??????????????????????????? if (isOnLink(routes, gw)) {

??????????????????????????????????????????? newIpWatchList.put(gw, getNeighborStateLocked(gw);}} }

//將處于鏈接狀態(tài)的DNS服務(wù)器加入IpWatchList

for (InetAddress nameserver : lp.getDnsServers()) {

?????????? if (isOnLink(routes, nameserver)) {

??????????????????? newIpWatchList.put(nameserver, getNeighborStateLocked(nameserver));}}

mIpWatchList = newIpWatchList;

mIpWatchListVersion++;

2房官、我們連續(xù)不斷地監(jiān)聽netlink消息(RTM_NEWNEIGH,RTM_DELNEIGH),僅僅關(guān)注在watch list中的neighbours網(wǎng)絡(luò)续滋。

public IpReachabilityMonitor(Context context, String ifName, Callback callback,

AvoidBadWifiTracker tracker) throws IllegalArgumentException {

...

//NetlinkSocketObserver類是用來建立Socket連接翰守,不斷地接受來自kernel的netlink消息,并并解析消息疲酌,判讀是否加入IpWatchList中蜡峰。具體信息可以參考下面NetlinkSocketObserver部分解析

mNetlinkSocketObserver = new NetlinkSocketObserver();

mObserverThread = new Thread(mNetlinkSocketObserver);

mObserverThread.start();

...

}


3、可以通過調(diào)用probeAll()方法來強(qiáng)制執(zhí)行probed所有在watch list中的鏈路neighbours網(wǎng)絡(luò)朗恳。不管什么時(shí)候湿颅,對(duì)于想驗(yàn)證鏈路上關(guān)鍵neighbour網(wǎng)絡(luò)依然可達(dá),這個(gè)方法是重要的粥诫,應(yīng)該被調(diào)用油航,比如當(dāng)在不同的BSSID之間Roaming的時(shí)候。

//將IpWatchList中Key集合取出來怀浆,然后通過調(diào)用probeNeighbor(int ifIndex, InetAddress ip)驗(yàn)證相應(yīng)的neighbour是否可達(dá)谊囚。

public void probeAll() {

//將IpWatchList中Key集合賦值給ipProbeList

Set<InetAddress>? ipProbeList = new HashSet();

ipProbeList.addAll(mIpWatchList.keySet());

for (InetAddress target : ipProbeList) {

final int returnValue = probeNeighbor(mInterfaceIndex, target);

/// M: Add UDP packet for ARP retry

//下面是MTK添加的策略怕享,針對(duì)probeNeighbor失敗的情況下,使用UDP重新觸發(fā)一次ARP請(qǐng)求

if (returnValue != 0) {

// Use UDP broadcast to trigger ARP procedure.

sendUdpBroadcast(target);}}}

private static int probeNeighbor(int ifIndex, InetAddress ip):

對(duì)于具體接口Index號(hào)上的給定Ip地址秒啦,使內(nèi)核Kernel執(zhí)行neighbour網(wǎng)絡(luò)可達(dá)性檢測(cè)(IPv4 ARP或 IPv6 ND)。

如果網(wǎng)絡(luò)可達(dá)性檢測(cè)請(qǐng)求成功傳輸?shù)絻?nèi)核kernel搀玖,返回0; 其他返回一個(gè)非0的錯(cuò)誤碼余境。

private static int probeNeighbor(int ifIndex, InetAddress ip) {

...

//將ip地址和相應(yīng)的接口號(hào)ifIndex封裝到PROBE消息中

final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(

1, ip, StructNdMsg.NUD_PROBE, ifIndex, null);

//創(chuàng)建NetlinkSocket,成功后進(jìn)行連接kernel, 然后發(fā)送消息灌诅;

最后接收消息芳来,并通過Netlink對(duì)消息進(jìn)行解析。

try (NetlinkSocket nlSocket = new NetlinkSocket(OsConstants.NETLINK_ROUTE)) {

nlSocket.connectToKernel();

nlSocket.sendMessage(msg, 0, msg.length, IO_TIMEOUT);

final ByteBuffer bytes = nlSocket.recvMessage(IO_TIMEOUT);

// recvMessage() guaranteed to not return null if it did not throw.

final NetlinkMessage response = NetlinkMessage.parse(bytes);

猜拾。即舌。。//后面依據(jù)不同的response 返回不同的值挎袜。

}}


4顽聂、如果處于NUD_FAILED狀態(tài)的neighbour網(wǎng)絡(luò)的丟失將會(huì)導(dǎo)致Ipv4 或者Ipv6配置變得不完整(配置丟失),我們將會(huì)調(diào)用提供的Callback#notifyLost()函數(shù)盯仪。

private void handleNeighborLost(String msg) {

? ? ? ? LinkProperties whatIfLp = new LinkProperties(mLinkProperties);

??????? for (Map.Entryentry : mIpWatchList.entrySet()) {

???????????????????? //遍歷IpWatchList中的所有neighbor紊搪,尋找value狀態(tài)為NUD_FAILED的

???????????????????? if (entry.getValue() != StructNdMsg.NUD_FAILED) {

?????????????????????????? continue;

????????????????????? }

? ? ? ? ? ? ? ? ? //從IpWatchList找到了value狀態(tài)為NUD_FAILED的neighbor, 獲取其IP地址;

? ? ? ? ? ? ? ? ? //遍歷mLinkProperties中路由Routes的網(wǎng)關(guān)是否有跟該IP地址一致的全景,如果有耀石,則從當(dāng)前的whatIfLp 中移除相應(yīng)的路由Routes。

? ? ? ? ? ? ? ? ? ip = entry.getKey();

????????????????? for (RouteInfo route : mLinkProperties.getRoutes()) {

????????????????? if (ip.equals(route.getGateway())) {

????????????????????????? whatIfLp.removeRoute(route);

???????????????? }

? ? ? ? ? ? ? //如果該IP地址不是IPv6 地址或者使能了避免badLink連接的性能爸黄,則從whatIfLp中移除Ip地址對(duì)應(yīng)的DNS服務(wù)器滞伟。

? ? ? ? ? ? ? ? if (avoidingBadLinks() || !(ip instanceof Inet6Address)) {

?????????????????????????? // We should do this unconditionally, but alas we cannot: b/31827713.

?????????????????????????? whatIfLp.removeDnsServer(ip);

??????????????? }

?????????? }

? ? ? ? //調(diào)用LinkProperties的compareProvisioning函數(shù)得到whatIfLp與原始的mLinkProperties的區(qū)別。

? ? ? ? ? delta = LinkProperties.compareProvisioning(mLinkProperties, whatIfLp);

? ? ? ? ? //如果delta值為ProvisioningChange.LOST_PROVISIONING炕贵,則回調(diào)函數(shù)notifyLost進(jìn)行配置丟失的處理梆奈;該回調(diào)函數(shù)的實(shí)現(xiàn)是在IpManager中,詳見IpManger中的分析称开。

????????? if (delta == ProvisioningChange.LOST_PROVISIONING) {

? ? ? ? ??????????? mCallback.notifyLost(ip, logMsg);

???????? }

}



Android - NetlinkSocketObserver


NetlinkSocketObserver簡介

在IpReachabilityMonitor類中有一個(gè)子類NetlinkSocketObserver類鉴裹。

在IpReachiabilityMonitor 構(gòu)造函數(shù)中會(huì)創(chuàng)建NetlinkSocketObserver對(duì)象,并對(duì)該對(duì)象進(jìn)行封裝钥弯,創(chuàng)建一個(gè)Thread類 對(duì)象径荔,并調(diào)用Thread類對(duì)象的Start方法,啟動(dòng)線程脆霎。

mNetlinkSocketObserver = new NetlinkSocketObserver();

mObserverThread = new Thread(mNetlinkSocketObserver);

mObserverThread.start();


NetlinkSocketObserver作用

NetlinkSocketObserver 類主要和Android Netlink 進(jìn)行交互总处。

Android netlink :frameworks/base/services/net/java/android/net/netlink/...

該類的作用主要是建立NETLINK_ROUTE Socket,綁定相應(yīng)的NetlinkSocketAddress睛蛛。然后無限循環(huán)接收kernelReply信息并對(duì)該消息進(jìn)行解析鹦马。


NetlinkSocketObserver實(shí)現(xiàn)

//通過實(shí)現(xiàn)Runnable接口創(chuàng)建線程胧谈,重寫run方法;

該類的作用就是建立NETLINK_ROUTE Socket荸频,綁定相應(yīng)的NetlinkSocketAddress菱肖。然后無限循環(huán)接收kernelReply信息并對(duì)該消息進(jìn)行解析。

關(guān)鍵接口實(shí)現(xiàn):

Run()

? -->parseNetlinkMessageBuffer(byteBuffer, whenMs)

? ? ? ? -->evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs);

private final class NetlinkSocketObserver implements Runnable

{

//建立NETLINK_ROUTE Socket旭从,綁定相應(yīng)的NetlinkSocketAddress稳强。然后無限循環(huán)接收kernelReply信息并對(duì)該消息進(jìn)行解析。

public void run() {

//1和悦、建立NETLINK_ROUTE Socket退疫,并綁定bind 相應(yīng)的NetlinkSocketAddress

setupNetlinkSocket();

//2、接收Kernel的Reply信息

byteBuffer = recvKernelReply();

//3鸽素、對(duì)接收到的KernelReply信息進(jìn)行解析

parseNetlinkMessageBuffer(byteBuffer, whenMs);

}

//將ByteBuffer解析為NetlinkMessage格式消息褒繁,并判斷消息類型,調(diào)用評(píng)估消息是否更新相應(yīng)ipadress的IpWatchList馍忽。

private void parseNetlinkMessageBuffer(ByteBuffer byteBuffer, long whenMs)

/*

//1棒坏、通過調(diào)用NetlinkMessage類將ByteBuffer解析為NetlinkMessage格式消息

final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer);

//2、判斷解析出現(xiàn)的NetlinkMessage消息類型遭笋,確保是RtNetlinkNeighborMessage消息才繼續(xù)進(jìn)行評(píng)估俊抵;如果是NetlinkErrorMessage或不是RtNetlinkNeighborMessage消息直接退出。

nlMsg instanceof NetlinkErrorMessage

nlMsg instanceof RtNetlinkNeighborMessage?

//3坐梯、調(diào)用evaluateRtNetlinkNeighborMessage對(duì)RtNetlinkNeighborMessage消息進(jìn)行評(píng)估徽诲。

evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs);

*/

//依據(jù)從RtNetlinkNeighborMessage獲取的msgType和nudState,對(duì)IpWatchList中相應(yīng)的InetAddress的nudState 進(jìn)行更新吵血。

private void evaluateRtNetlinkNeighborMessage

(RtNetlinkNeighborMessage neighMsg, long whenMs)

/*

//1谎替、從neighMsg取目的IP地址,并判斷該IP地址是否在IpWatchList中蹋辅,不在則直接退出函數(shù)返回

final InetAddress destination = neighMsg.getDestination();

//2钱贯、從neighMsg取msgType和nudState,并根據(jù)他們進(jìn)行IpWatchList 的更新

final short msgType = neighMsg.getHeader().nlmsg_type;

final short nudState = ndMsg.ndm_state;

final short value =

(msgType == NetlinkConstants.RTM_DELNEIGH) ? StructNdMsg.NUD_NONE: nudState;

mIpWatchList.put(destination, value);

//3侦另、如果nudState為NUD_FAILED狀態(tài)秩命,則執(zhí)行handleNeighborLost動(dòng)作

if (nudState == StructNdMsg.NUD_FAILED) {

handleNeighborLost(eventMsg);? //這個(gè)詳見IpReachiabilityMonitor的實(shí)現(xiàn)方式的第4部分。

*/

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末褒傅,一起剝皮案震驚了整個(gè)濱河市弃锐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌殿托,老刑警劉巖霹菊,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異支竹,居然都是意外死亡旋廷,警方通過查閱死者的電腦和手機(jī)鸠按,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來饶碘,“玉大人目尖,你說我怎么就攤上這事≡耍” “怎么了瑟曲?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長绪囱。 經(jīng)常有香客問我测蹲,道長莹捡,這世上最難降的妖魔是什么鬼吵? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮篮赢,結(jié)果婚禮上齿椅,老公的妹妹穿的比我還像新娘。我一直安慰自己启泣,他們只是感情好涣脚,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著寥茫,像睡著了一般遣蚀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上纱耻,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天芭梯,我揣著相機(jī)與錄音,去河邊找鬼弄喘。 笑死玖喘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蘑志。 我是一名探鬼主播累奈,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼急但!你這毒婦竟也來了澎媒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤波桩,失蹤者是張志新(化名)和其女友劉穎旱幼,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體突委,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡柏卤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年冬三,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缘缚。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡勾笆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出桥滨,到底是詐尸還是另有隱情窝爪,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布齐媒,位于F島的核電站蒲每,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏喻括。R本人自食惡果不足惜邀杏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望唬血。 院中可真熱鬧望蜡,春花似錦、人聲如沸拷恨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽腕侄。三九已至小泉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間冕杠,已是汗流浹背微姊。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拌汇,地道東北人柒桑。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像噪舀,于是被迫代替她去往敵國和親魁淳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

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