iOS開發(fā)——socket編程和GCDAsyncSocket

一室叉、socket

1.網(wǎng)絡(luò)體系結(jié)構(gòu)和網(wǎng)絡(luò)協(xié)議

在說socket之前凿可,先要簡單說一說網(wǎng)絡(luò)體系結(jié)構(gòu)揪胃。OSI(Open System Interconnection Reference艾君, 開放式系統(tǒng)互聯(lián)通信參考)將計(jì)算機(jī)網(wǎng)絡(luò)體系結(jié)構(gòu)劃分為以下七層:

網(wǎng)絡(luò)七層

其中媒體層是網(wǎng)絡(luò)工程師所研究的對象署海,主機(jī)層則是用戶所面向和關(guān)心的內(nèi)容吗购。

常應(yīng)用到的傳輸協(xié)議有http協(xié)議、tcp/udp協(xié)議砸狞、ip協(xié)議分別對應(yīng)于應(yīng)用層捻勉、傳輸層、網(wǎng)絡(luò)層刀森。TCP/IP是傳輸層協(xié)議踱启,主要解決數(shù)據(jù)如何在網(wǎng)絡(luò)中傳輸;而HTTP是應(yīng)用層協(xié)議研底,主要解決如何包裝數(shù)據(jù)埠偿。

我們在傳輸數(shù)據(jù)時(shí),可以只使用傳輸層(TCP/IP)榜晦,那樣的話由于沒有應(yīng)用層冠蒋,便無法識別數(shù)據(jù)內(nèi)容,如果想要使傳輸?shù)臄?shù)據(jù)有意義乾胶,則必須使用應(yīng)用層協(xié)議抖剿,應(yīng)用層協(xié)議很多,有HTTP识窿、FTP斩郎、TELNET等等,也可以自己定義應(yīng)用層協(xié)議喻频。WEB使用HTTP作傳輸層協(xié)議缩宜,以封裝HTTP文本信息,然 后使用TCP/IP做傳輸層協(xié)議將它發(fā)送到網(wǎng)絡(luò)上甥温。Socket是對TCP/IP協(xié)議的封裝脓恕,Socket本身并不是協(xié)議膜宋,而是一個(gè)調(diào)用接口(API)窿侈,通過Socket炼幔,我們才能使用TCP/IP協(xié)議。

2.Http和Socket連接區(qū)別

2.1 socket連接:

建立起一個(gè)TCP連接需要經(jīng)過“三次握手”:
第一次握手:客戶端發(fā)送syn包(syn=j)到服務(wù)器史简,并進(jìn)入SYN_SEND狀態(tài)乃秀,等待服務(wù)器確認(rèn);
第二次握手:服務(wù)器收到syn包圆兵,必須確認(rèn)客戶的SYN(ack=j+1)跺讯,同時(shí)自己也發(fā)送一個(gè)SYN包(syn=k),即SYN+ACK包殉农,此時(shí)服務(wù)器進(jìn)入SYN_RECV狀態(tài)刀脏;
第三次握手:客戶端收到服務(wù)器的SYN+ACK包,向服務(wù)器發(fā)送確認(rèn)包ACK(ack=k+1)超凳,此包發(fā)送完畢愈污,客戶端和服務(wù)器進(jìn)入ESTABLISHED狀態(tài),完成三次握手轮傍。
握手過程中傳送的包里不包含數(shù)據(jù)暂雹,三次握手完畢后,客戶端與服務(wù)器才正式開始傳送數(shù)據(jù)创夜。斷開連接時(shí)服務(wù)器和客戶端均可以主動發(fā)起斷開TCP連接的請求杭跪,斷開過程需要經(jīng)過“四次握手”。

socket連接就是所謂的長連接驰吓,理論上客戶端和服務(wù)器端一旦加你其連接將不會主動斷掉涧尿;但是由于各種環(huán)境因素可能會連接斷開,比如說:服務(wù)器端或客戶端主機(jī)down了檬贰,網(wǎng)絡(luò)故障姑廉,或者兩者之間長時(shí)間沒有傳輸數(shù)據(jù),網(wǎng)絡(luò)防火墻可能會斷開該連接以釋放網(wǎng)絡(luò)資源偎蘸。所以當(dāng)一個(gè)socket連接中沒有數(shù)據(jù)傳輸?shù)臅r(shí)候庄蹋,那么為了維持連接需要發(fā)送心跳消息,具體心跳消息格式是開發(fā)者自己定義的迷雪。

2.2 HTTP連接

HTTP協(xié)議即超文本傳送協(xié)議(HypertextTransfer Protocol )限书,是Web聯(lián)網(wǎng)的基礎(chǔ),也是手機(jī)聯(lián)網(wǎng)常用的協(xié)議之一章咧,HTTP協(xié)議是建立在TCP協(xié)議之上的一種應(yīng)用倦西。
HTTP連接最顯著的特點(diǎn)是客戶端發(fā)送的每次請求都需要服務(wù)器回送響應(yīng),在請求結(jié)束后赁严,會主動釋放連接扰柠。從建立連接到關(guān)閉連接的過程稱為“一次連接”粉铐。
1)在HTTP 1.0中,客戶端的每次請求都要求建立一次單獨(dú)的連接卤档,在處理完本次請求后蝙泼,就自動釋放連接。
2)在HTTP 1.1中則可以在一次連接中處理多個(gè)請求劝枣,并且多個(gè)請求可以重疊進(jìn)行汤踏,不需要等待一個(gè)請求結(jié)束后再發(fā)送下一個(gè)請求。
由于HTTP在每次請求結(jié)束后都會主動釋放連接舔腾,因此HTTP連接是一種“短連接”溪胶,要保持客戶端程序的在線狀態(tài),需要不斷地向服務(wù)器發(fā)起連接請求稳诚。通常的 做法是即時(shí)不需要獲得任何數(shù)據(jù)哗脖,客戶端也保持每隔一段固定的時(shí)間向服務(wù)器發(fā)送一次“保持連接”的請求,服務(wù)器在收到該請求后對客戶端進(jìn)行回復(fù)扳还,表明知道客戶端“在線”才避。若服務(wù)器長時(shí)間無法收到客戶端的請求,則認(rèn)為客戶端“下線”普办,若客戶端長時(shí)間無法收到服務(wù)器的回復(fù)工扎,則認(rèn)為網(wǎng)絡(luò)已經(jīng)斷開。

二.GCDAsyncSocket

在iOS開發(fā)中使用socket衔蹲,一般都是用第三方庫GCDAsyncSocket(雖然也有原生CFSocket)肢娘。
GCDAsyncSocket 下載地址: GCDAsyncSocket

使用之前需要先在項(xiàng)目引入ASyncSocket庫:

  1. 把ASyncSocket庫源碼加入項(xiàng)目:只需要增加RunLoop目錄中的AsyncSocket.h、AsyncSocket.m舆驶、AsyncUdpSocket.h和AsyncUdpSocket.m四個(gè)文件橱健。
  2. 在項(xiàng)目增加CFNetwork框架:在Framework目錄右健,選擇Add-->Existing Files... , 選擇 CFNetwork.framework

下面開始介紹一下如何使用ASyncSocket:

一般來說,一個(gè)用戶只需要建立一個(gè)socket長連接拘荡,所以可以用單例類方便使用。

單例方法

// 創(chuàng)建單例
+ (Singleton *) sharedInstance
{
    static Singleton *sharedInstace = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstace = [[self alloc] initPrivate];
    });
    return sharedInstace;
}

// 私有創(chuàng)建方法珊皿,不公開
- (instancetype)initPrivate {
    if (self = [super init]) {
        _lockStr = @"1234";
    }
    return self;
}

// 廢除init創(chuàng)建方法
- (instancetype)init {
    @throw [NSException exceptionWithName:@"初始化異常" reason:@"不允許通過init方法創(chuàng)建對象" userInfo:nil];
}

建立socket長連接

#define TIME_OUT 20

// 建立socket連接
-(void)socketConnectHost{
    _socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
    NSLog(@"連接服務(wù)器");
    NSError *error = nil;
    [_socket connectToHost:_socketHost onPort:_socketPort withTimeout:TIME_OUT error:&error];
}

// socket成功連接回調(diào)
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {
    NSLog(@"成功連接到%@:%d",host,port);
    _bufferData = [[NSMutableData alloc] init]; // 存儲接收數(shù)據(jù)的緩存區(qū)
    [_socket readDataWithTimeout:-1 tag:99];
}

心跳###

@property (nonatomic, retain) NSTimer             *heartTimer;   // 心跳計(jì)時(shí)器

在連接成功的回調(diào)方法里巨税,啟動定時(shí)器,每隔2秒向服務(wù)器發(fā)送固定的消息來檢測長連接草添。

// 心跳連接
-(void)longConnectToSocket{
    根據(jù)服務(wù)器要求發(fā)送固定格式的數(shù)據(jù),假設(shè)為指令@"longConnect",但是一般不會是這么簡單的指令
    NSString *longConnect = @"longConnect";
    NSData   *dataStream  = [longConnect dataUsingEncoding:NSUTF8StringEncoding];
    [_socket writeData:dataStream withTimeout:1 tag:1];
}

斷開連接###

  • 主動斷開
- (void)cutOffSocket {
    [_socket disconnect];
    _socket.userData =  @(SocketOfflineByUser);
    NSLog(@"斷開連接");
}
  • 被動斷開
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
    if (err.code == 57) {
        _socket.userData = @(SocketOfflineByWifiCut); // wifi斷開
    }
    else {
        _socket.userData =  @(SocketOfflineByServer);  // 服務(wù)器掉線
    }
    NSLog(@"斷開連接屠凶,錯(cuò)誤:%@",err);
}

錯(cuò)誤碼請見 sys/errno.h

發(fā)送消息

// 發(fā)消息
- (void)sendMessage:(NSData *)data {
    [_socket writeData:data withTimeout:TIME_OUT tag:10];
}

// wirte成功
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
    // 持續(xù)接收數(shù)據(jù)
    // 超時(shí)設(shè)置為附屬肆资,表示不會使用超時(shí)
    [_socket readDataWithTimeout:-1 tag:tag];
}

接收消息

-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
    // 在這里處理消息
    [self disposeBufferData:data];

    //持續(xù)接收服務(wù)端的數(shù)據(jù)
    [sock readDataWithTimeout:-1 tag:tag];
}

粘包

最后說說戰(zhàn)報(bào)的問題和相關(guān)處理。粘包是指發(fā)送方發(fā)送的若干包數(shù)據(jù)到接收方接收時(shí)粘成一包迅耘,TCP傳輸往往會出現(xiàn)粘包贱枣。出現(xiàn)粘包現(xiàn)象的原因是多方面的,它既可能由發(fā)送方造成颤专,也可能由接收方造成。發(fā)送方引起的粘包是由TCP協(xié)議本身造成的钠乏,TCP為提高傳輸效率栖秕,發(fā)送方往往要收集到足夠多的數(shù)據(jù)后才發(fā)送一包數(shù)據(jù)。若連續(xù)幾次發(fā)送的數(shù)據(jù)都很少晓避,通常TCP會根據(jù)優(yōu)化算法把這些數(shù)據(jù)合成一包后一次發(fā)送出去簇捍,這樣接收方就收到了粘包數(shù)據(jù)。接收方引起的粘包是由于接收方用戶進(jìn)程不及時(shí)接收數(shù)據(jù)俏拱,從而導(dǎo)致粘包現(xiàn)象暑塑。這是因?yàn)榻邮辗较劝咽盏降臄?shù)據(jù)放在系統(tǒng)接收緩沖區(qū),用戶進(jìn)程從該緩沖區(qū)取數(shù)據(jù)锅必,若下一包數(shù)據(jù)到達(dá)時(shí)前一包數(shù)據(jù)尚未被用戶進(jìn)程取走事格,則下一包數(shù)據(jù)放到系統(tǒng)接收緩沖區(qū)時(shí)就接到前一包數(shù)據(jù)之后,而用戶進(jìn)程根據(jù)預(yù)先設(shè)定的緩沖區(qū)大小從系統(tǒng)接收緩沖區(qū)取數(shù)據(jù)搞隐,這樣就一次取到了多包數(shù)據(jù)驹愚。

為了避免粘包現(xiàn)象,可采取以下幾種措施劣纲。一是對于發(fā)送方引起的粘包現(xiàn)象逢捺,用戶可通過編程設(shè)置來避免,TCP提供了強(qiáng)制數(shù)據(jù)立即傳送的操作指令push癞季,TCP軟件收到該操作指令后劫瞳,就立即將本段數(shù)據(jù)發(fā)送出去,而不必等待發(fā)送緩沖區(qū)滿绷柒;二是對于接收方引起的粘包志于,則可通過優(yōu)化程序設(shè)計(jì)、精簡接收進(jìn)程工作量辉巡、提高接收進(jìn)程優(yōu)先級等措施恨憎,使其及時(shí)接收數(shù)據(jù),從而盡量避免出現(xiàn)粘包現(xiàn)象;三是由接收方控制憔恳,將一包數(shù)據(jù)按結(jié)構(gòu)字段瓤荔,人為控制分多次接收,然后合并钥组,通過這種手段來避免粘包输硝。

以上提到的三種措施,都有其不足之處程梦。第一種編程設(shè)置方法雖然可以避免發(fā)送方引起的粘包点把,但它關(guān)閉了優(yōu)化算法郎逃,降低了網(wǎng)絡(luò)發(fā)送效率褒翰,影響應(yīng)用程序的性能优训,一般不建議使用各聘。第二種方法只能減少出現(xiàn)粘包的可能性躲因,但并不能完全避免粘包,當(dāng)發(fā)送頻率較高時(shí)搁嗓,或由于網(wǎng)絡(luò)突發(fā)可能使某個(gè)時(shí)間段數(shù)據(jù)包到達(dá)接收方較快箱靴,接收方還是有可能來不及接收衡怀,從而導(dǎo)致粘包。第三種方法雖然避免了粘包够委,但應(yīng)用程序的效率較低茁帽,對實(shí)時(shí)應(yīng)用的場合不適合。

一種比較周全的對策是:接收方創(chuàng)建一預(yù)處理線程吊输,對接收到的數(shù)據(jù)包進(jìn)行預(yù)處理铁追,將粘連的包分開。具體的方法就是在發(fā)送數(shù)據(jù)是在數(shù)據(jù)前加入包頭扭屁,接收時(shí)首先將待處理的接收數(shù)據(jù)流(長度為m)強(qiáng)行轉(zhuǎn)換成預(yù)定的結(jié)構(gòu)數(shù)據(jù)形式料滥,并從中取出結(jié)構(gòu)數(shù)據(jù)長度字段n埋泵,而后根據(jù)n計(jì)算得到第一包數(shù)據(jù)長度丽声。
1)若n<m雁社,則表明數(shù)據(jù)流內(nèi)容超過一段完整的數(shù)據(jù)結(jié)構(gòu)晒骇,將前n長度的數(shù)據(jù)截取并進(jìn)行處理洪囤,對于剩下的m-n長度數(shù)據(jù)重復(fù)上述解析和判斷瘤缩。
2)若n=m,則表明數(shù)據(jù)流內(nèi)容恰好是一完整結(jié)構(gòu)數(shù)據(jù)锦溪,直接將其存入臨時(shí)緩沖區(qū)即可刻诊。
3)若n>m牺丙,則表明數(shù)據(jù)流內(nèi)容尚不夠構(gòu)成一完整結(jié)構(gòu)數(shù)據(jù),需留待與下一包數(shù)據(jù)合并后再行處理亿昏。

下面是我和服務(wù)器約定好的包頭和包的類型

// 定義包頭
typedef struct tagNetPacketHead
{
    int version;                      //版本
    int eMainType;                  //包類型主協(xié)議
    int eSubType;                    //包類型子協(xié)議
    unsigned int nLen;              //包體長度
} NetPacketHead;

// 定義發(fā)包類型
typedef struct tagNetPacket
{
    NetPacketHead netPacketHead;      //包頭
    unsigned char *packetBody;      //包體
} NetPacket;

收到數(shù)據(jù)時(shí)先將收到的數(shù)據(jù)放到緩存中龙优,然后進(jìn)行上述判斷事秀。

- (void)disposeBufferData:(NSData *)data {
    @synchronized (self.lockStr) {
        [_bufferData appendData:data];
        while (_bufferData.length >= 16) {
            struct tagNetPacketHead head;

            [_bufferData getBytes:&head range:NSMakeRange(0, 16)];
            while (_bufferData.length >= 16 && !(head.version == 1 && head.eMainType > -10 && head.eMainType < 1000 && head.eSubType > - 10 && head.eSubType < 1000)) {
                int a = (int)_bufferData.length - 1;
                _bufferData = [_bufferData subdataWithRange:NSMakeRange(1, a)].mutableCopy;
                if (_bufferData.length >= 16) {
                    [_bufferData getBytes:&head range:NSMakeRange(0, 16)];
                }
            }
            
            BOOL isIn = !(head.nLen > (_bufferData.length - 16));
            if (isIn && _bufferData.length >= 16) {
                NSMutableData *pendingData = [NSMutableData data];
                if (head.eSubType == -1) {
                    pendingData = [_bufferData subdataWithRange:NSMakeRange(4, 4)].mutableCopy;
                    [pendingData appendData:[_bufferData subdataWithRange:NSMakeRange(16, head.nLen)]];
                }
                else {
                    pendingData = [_bufferData subdataWithRange:NSMakeRange(4, 8)].mutableCopy;
                    NSLog(@"%d", head.nLen);
                    [pendingData appendData:[_bufferData subdataWithRange:NSMakeRange(16, head.nLen)]];
                }

                [DisposeManager disposeData:pendingData num:head.eMainType];
                int totalLen = _bufferData.length;
                _bufferData = [_bufferData subdataWithRange:NSMakeRange(16 + head.nLen, totalLen - 16 - head.nLen)].mutableCopy;
            }
        }
    }
}

注意:在這里加入線程鎖@synchronized (self.lockStr)宰衙,防止緩沖區(qū)同時(shí)被多個(gè)線程訪問發(fā)生緩沖區(qū)數(shù)據(jù)混亂供炼。

發(fā)送數(shù)據(jù)時(shí)則需要將數(shù)據(jù)按照約定的結(jié)構(gòu)進(jìn)行處理袋哼,在前邊加上包頭涛贯。

- (NSMutableData *)linkDataWithVersion:(NSData *)versionData mainType:(int)mainType subType:(int)subType packetBody:(NSData *)packetBody{
    if (!versionData) {
        int version = 1;
        versionData = [NSMutableData dataWithBytes:&version length:sizeof(version)];
    }
    NSMutableData *mainTypeData = [NSMutableData dataWithBytes:&mainType length:sizeof(mainType)];

    NSMutableData *subTypeData = [NSMutableData dataWithBytes:&subType length:sizeof(subType)];

    unsigned int len;
    if (packetBody) {
        len = packetBody.length;
    }
    else {
        len = 0;
    }

    NSMutableData *lenData = [NSMutableData dataWithBytes:&len length:sizeof(len)];

    NSMutableData *sendData = [[NSMutableData alloc] init];
    [sendData appendData:versionData];
    [sendData appendData:mainTypeData];
    [sendData appendData:subTypeData];
    [sendData appendData:lenData];
    [sendData appendData:packetBody];

    return sendData.mutableCopy;
}

注:這里的mainTypeData和subTypeData只是和本工程相關(guān)的主協(xié)議和子協(xié)議弟翘,并不具備普遍性稀余。
注:version和服務(wù)器端約定好是1趋翻。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嘿歌,一起剝皮案震驚了整個(gè)濱河市宙帝,隨后出現(xiàn)的幾起案子步脓,更是在濱河造成了極大的恐慌浩螺,老刑警劉巖仍侥,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件农渊,死亡現(xiàn)場離奇詭異,居然都是意外死亡传于,警方通過查閱死者的電腦和手機(jī)沼溜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門系草,熙熙樓的掌柜王于貴愁眉苦臉地迎上來找都,“玉大人廊酣,你說我怎么就攤上這事。” “怎么了隐解?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵煞茫,是天一觀的道長续徽。 經(jīng)常有香客問我钦扭,道長客情,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任梭伐,我火速辦了婚禮糊识,結(jié)果婚禮上赂苗,老公的妹妹穿的比我還像新娘哑梳。我一直安慰自己,他們只是感情好绘盟,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布鸠真。 她就那樣靜靜地躺著,像睡著了一般龄毡。 火紅的嫁衣襯著肌膚如雪吠卷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天沦零,我揣著相機(jī)與錄音祭隔,去河邊找鬼。 笑死路操,一個(gè)胖子當(dāng)著我的面吹牛疾渴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播屯仗,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼搞坝,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了魁袜?” 一聲冷哼從身側(cè)響起桩撮,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤融师,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后后控,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體张抄,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡极谊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年咙边,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了淑蔚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盟戏。...
    茶點(diǎn)故事閱讀 39,703評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蝇摸,死狀恐怖民镜,靈堂內(nèi)的尸體忽然破棺而出畔况,到底是詐尸還是另有隱情馋嗜,我是刑警寧澤听皿,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布九府,位于F島的核電站煌妈,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜泼舱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望宋渔。 院中可真熱鬧,春花似錦辜限、人聲如沸吩坝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至抖部,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間崭篡,已是汗流浹背琉闪。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留壮池,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓刷喜,卻偏偏與公主長得像,于是被迫代替她去往敵國和親浊闪。 傳聞我的和親對象是個(gè)殘疾皇子恼布,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評論 2 353

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

  • 1、TCP狀態(tài)linux查看tcp的狀態(tài)命令:1)搁宾、netstat -nat 查看TCP各個(gè)狀態(tài)的數(shù)量2)折汞、lso...
    北辰青閱讀 9,423評論 0 11
  • 歃血征途路漫漫,長歌一曲戎裝寒猛铅。 馬革裹尸未有淚字支,豈知青梅不復(fù)還?
    南柯森林迷了鹿閱讀 301評論 0 0
  • 爸爸奸忽,你可以讓媽媽也坐在你脖子上嗎 這樣?jì)寢尵筒粫刀饰铱偸潜荒銓欀?這樣?jì)寢屢部梢钥吹竭h(yuǎn)處向我們跑來的小兔子 媽...
    斯人會閱讀 328評論 0 0
  • 坐標(biāo):九省通衢的火爐城武漢 最近受了頗多打擊栗菜,總的來說問題出在缺錢上欠雌。 來自于湖北某N線縣城的我,因?yàn)樯洗髮W(xué)來到了...
    莊生7小夢閱讀 188評論 0 1
  • 一疙筹、身體近況及目標(biāo)期望 9.9測量三圍:83/73(肚臍)/93 核心訴求: 1富俄、打好基礎(chǔ):基礎(chǔ)動作的梳理和糾正,...
    Rene817閱讀 291評論 0 0