日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

c++项目——聊天室——第一节

發(fā)布時(shí)間:2023/12/20 c/c++ 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++项目——聊天室——第一节 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

c++項(xiàng)目——聊天室——第一節(jié)

  • 概述
  • 引言
  • 聊天室初步
    • ????? 1 總體設(shè)計(jì)
    • ????? 2 思路設(shè)計(jì)
    • ????? 3 數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)(細(xì)節(jié)設(shè)計(jì))
      • ???????(1)分析消息協(xié)議部分
      • ???????(2)分析客戶(hù)端
      • ???????(3)分析服務(wù)器
  • 聊天室1.0
    • 運(yùn)行效果
    • 聊天室1.0代碼簡(jiǎn)析(具體分析會(huì)在聊天室1.2的版本里)
      • 客戶(hù)端
      • 1、連接+讀服務(wù)器數(shù)據(jù)
      • 2、向服務(wù)器寫(xiě)數(shù)據(jù)
      • 服務(wù)器
      • 1、接收客戶(hù)端消息
      • 2、向客戶(hù)端寫(xiě)
  • 有趣的點(diǎn)
    • 異步循環(huán)調(diào)用為什么不爆棧?
    • 為什么要使用self(shared_from_this)?
  • 聊天室1.0 github地址:
  • 參考文獻(xiàn)

概述

???????本節(jié)內(nèi)容是在 如何學(xué)習(xí)編程 之后進(jìn)一步由理論結(jié)合實(shí)踐去驗(yàn)證和加深該學(xué)習(xí)思想,為了方便起見(jiàn),不會(huì)再過(guò)多的闡述先驗(yàn)知識(shí),因此若是在閱讀過(guò)程中出現(xiàn)因先驗(yàn)知識(shí)不足而導(dǎo)致的難以理解的情況,請(qǐng)自行學(xué)習(xí)相關(guān)的先驗(yàn)知識(shí)

???????因?yàn)閏++這門(mén)語(yǔ)言學(xué)習(xí)起來(lái)總有一定的難度,除了語(yǔ)言本身的原因以外,由于學(xué)的人相對(duì)較少,學(xué)精通的人更少,導(dǎo)致在推廣方面,無(wú)論是人數(shù)還是質(zhì)量都難以保證。

???????自己在剛開(kāi)始學(xué)c++的時(shí)候,出現(xiàn)過(guò)很多問(wèn)題,影響最大的還是以下幾點(diǎn):

  • 1 資源相對(duì)較少,當(dāng)時(shí)自己找資源的能力也比較有限。
  • 2 資源參差不齊,有些博主自己都沒(méi)有完全理解,寫(xiě)了一大堆專(zhuān)業(yè)術(shù)語(yǔ)出來(lái)裝逼的。
  • 3 c++比較權(quán)威的書(shū)對(duì)于c++初學(xué)者不是很友好,因?yàn)闄?quán)威書(shū)籍很多先驗(yàn)知識(shí)都默認(rèn)你會(huì)了,但這也沒(méi)辦法。

???????看本篇文章的時(shí)候先看目錄,為了照顧c++小白有些地方寫(xiě)的比較細(xì)(俗話(huà)說(shuō)比價(jià)啰嗦),想看哪個(gè)部分直接目錄索引點(diǎn)過(guò)去即可。

???????寫(xiě)這篇文章除了有借此加深鞏固自己之前所學(xué)以外,也希望自己的文章可以幫助到更多的c++小白,讓越來(lái)越多的人喜歡上c++,愿c++經(jīng)久不衰。

引言

???????再次聲明,本篇文章是讓小白過(guò)渡到初學(xué)者的文章,因?yàn)楸救艘彩浅鯇W(xué)者,所以掌握的知識(shí)的全面程度和深度肯定是有限的,但學(xué)習(xí)本身就是不斷的擴(kuò)寬自己的廣度和深度,所以這很正常。就如同牛頓力學(xué)過(guò)度到量子力學(xué)一樣,牛頓力學(xué)沒(méi)有錯(cuò),量子力學(xué)也沒(méi)有錯(cuò),只是適用范圍不同罷了,或者說(shuō)量子力學(xué)的適用范圍更大,但不管怎么說(shuō),能在一定范圍內(nèi)正確解釋世界規(guī)律的,我覺(jué)得就是好理論。

???????先驗(yàn)知識(shí)聲明:在進(jìn)入聊天室的學(xué)習(xí)之前,必須要有一定的c++基礎(chǔ)知識(shí)和計(jì)算機(jī)相關(guān)的基礎(chǔ)知識(shí),沒(méi)有這些基礎(chǔ),什么牛鬼蛇神來(lái)了都沒(méi)有,就算是所謂的“天才、聰明人”,也只是通過(guò)類(lèi)比的方式,結(jié)合他自己之前類(lèi)似的經(jīng)歷推出來(lái)的(我對(duì)天才這個(gè)詞很反感,我覺(jué)得就是騙騙世人,給人們找借口的詞匯,如有不適敬請(qǐng)見(jiàn)諒),所以如果沒(méi)有掌握這些知識(shí),你看起來(lái)無(wú)比難受是很正常的事情。
???????具體的先驗(yàn)知識(shí):(其中黃色是必須掌握,淺色黑體是掌握了對(duì)細(xì)節(jié)的把握會(huì)更好)
??????? 1、c++基礎(chǔ)部分:類(lèi)初步(如構(gòu)造函數(shù)析構(gòu)函數(shù)、公有繼承私有繼承等)、STL基本使用(deque、vector、list、string、chrono時(shí)間庫(kù))、命名空間、枚舉、基本關(guān)鍵字(typedef、using)、const引用和值傳遞的區(qū)別、內(nèi)存對(duì)齊、右值引用和左值引用的區(qū)別、異常、c++11新特性(加強(qiáng)for循環(huán)、智能指針)還有其他c和c++相同的部分、c++多線(xiàn)程基礎(chǔ)。
??????? 2、計(jì)算機(jī)網(wǎng)絡(luò)基礎(chǔ):c++asio網(wǎng)絡(luò)庫(kù)簡(jiǎn)單api使用、tcp報(bào)文格式、計(jì)算機(jī)網(wǎng)絡(luò)數(shù)據(jù)是如何從一臺(tái)主機(jī)上經(jīng)過(guò)5層模型(或者7層參考模型)到達(dá)另一臺(tái)主機(jī)的宏觀了解、同步異步的知識(shí)。
??????? 3、liunx基礎(chǔ):liunx最基本命令、liunx下cmake使用、liunx非常基本的腳本編寫(xiě)。
??????? 4、其他:像google protobuf等序列工具的使用、為什么要序列化、protobuf為什么快等。

??????? 細(xì)心的同學(xué)可能發(fā)現(xiàn)了,為啥我沒(méi)有把c++多線(xiàn)程標(biāo)記為必會(huì)呢?因?yàn)槲覀冞@個(gè)聊天室是一個(gè)循序漸進(jìn)的版本,因此如果沒(méi)到后面多線(xiàn)程的版本,不需要掌握c++多線(xiàn)程基礎(chǔ)當(dāng)然也可以駕馭。
??????? 還有就是,如果對(duì)c++內(nèi)存掌握程度高的話(huà),對(duì)一些細(xì)節(jié)的理解肯定還會(huì)更好,畢竟我們學(xué)習(xí)知識(shí)肯定是知其然還要知其所以然,再功利點(diǎn)說(shuō):遇到bug你也能知道原因然后快速定位去解決嘛。

聊天室初步


????? 1 總體設(shè)計(jì)

??????? 正所謂:兵馬未動(dòng),糧草先行;理論是用來(lái)更好指導(dǎo)實(shí)踐的。有一個(gè)好的架構(gòu)體系,或者說(shuō)在設(shè)計(jì)之初就考慮好很多東西的話(huà),對(duì)后面無(wú)論是出問(wèn)題還是迭代肯定都會(huì)更好解決。(可以結(jié)合 如何學(xué)習(xí)編程 提到的守恒思想去分析)。

??????? 無(wú)論是設(shè)計(jì)和分析問(wèn)題,首先要把握的就是他的核心,用哲學(xué)的話(huà)來(lái)說(shuō)就是:把握事物的主要矛盾。其實(shí)也就是把握事物的本質(zhì)。

??????? 聊天室聊天室,核心肯定是提供一個(gè)較為舒適的聊天服務(wù)。把握本質(zhì)以后,接下來(lái)我們做的事情是什么?——計(jì)算機(jī)分治思想,或者簡(jiǎn)單點(diǎn)說(shuō),把問(wèn)題分解。
??????? 其實(shí)細(xì)心的同學(xué)在生活中就可以觀察到:無(wú)論我們做任何事情,無(wú)形之中其實(shí)就已經(jīng)把這件事情分成若干字問(wèn)題進(jìn)行處理了。
??????? 比如在吃飯的時(shí)候,先拿起筷子,做好姿勢(shì)、選中要夾的菜、計(jì)算筷子到要夾的菜要走什么樣的路徑、夾中菜后把握怎么樣的力度可以不讓菜掉下來(lái)…

??????? 回到正題,那么我們?cè)?strong>如何把問(wèn)題分解呢——剪取不重要細(xì)節(jié)。借鑒或者類(lèi)比之前吃飯的例子,舒適的聊天室,本質(zhì)上就是多人之間進(jìn)行聊天,那我們先分析兩個(gè)人的情況,也先不管舒不舒適的問(wèn)題,那現(xiàn)在的問(wèn)題就變成了——兩個(gè)人的聊天室。
??????? 如果加入服務(wù)器——客戶(hù)端的模型思想:服務(wù)器用來(lái)接收和發(fā)送這兩個(gè)人的消息,客戶(hù)端負(fù)責(zé)(從命令行)接收消息,并交由服務(wù)器處理,同時(shí)還會(huì)接受來(lái)自服務(wù)器的消息。
??????? 這其實(shí)還是有點(diǎn)抽象,簡(jiǎn)單點(diǎn)說(shuō),舉個(gè)例子:A和B同學(xué)聊天,現(xiàn)在A同學(xué)想對(duì)B同學(xué)說(shuō) “ni hao”,那么簡(jiǎn)單至極有兩種方式:1 A直接給B發(fā)消息。 2 A給一個(gè)中轉(zhuǎn)站發(fā)消息,由這個(gè)中轉(zhuǎn)站給B發(fā)消息。
??????? 有的同學(xué)可能會(huì)說(shuō):“哎呀,那肯定是第一種了,第二種這么麻煩”。但是我們簡(jiǎn)化問(wèn)題的時(shí)候也不能忽略原本的內(nèi)容——也就是俗話(huà)說(shuō) 未雨綢繆。現(xiàn)在是兩個(gè)同學(xué)發(fā)消息,如果是五個(gè)同學(xué)、十個(gè)同學(xué)呢,這就不好處理了。所以目前我們就使用方法2。

??????? 到這,我們的1.0版本的聊天室已經(jīng)逐漸浮出水面了:A同學(xué)和中轉(zhuǎn)站建立連接,之后向中轉(zhuǎn)站建立連接;B同學(xué)和中轉(zhuǎn)站也建立連接,接受中轉(zhuǎn)站發(fā)送過(guò)來(lái)A的消息。
??????? 然后我們發(fā)現(xiàn),無(wú)論有多少個(gè)同學(xué),都要和這個(gè)中轉(zhuǎn)站建立連接,而每一位同學(xué)做的動(dòng)作都是差不多的——和中轉(zhuǎn)站建立連接、發(fā)送或接收中轉(zhuǎn)站的消息。
??????? 如果把中轉(zhuǎn)站換個(gè)名字——服務(wù)器。把每個(gè)同學(xué)的動(dòng)作邏輯換個(gè)名字——客戶(hù)端。
??????? 那么聊天室1.0的雛形就出來(lái)了——服務(wù)器用于和客戶(hù)端連接并收發(fā)消息;客戶(hù)端用于接收用戶(hù)輸入并收發(fā)服務(wù)器的消息

????? 2 思路設(shè)計(jì)

??????? 下面我們就來(lái)逐步分析服務(wù)器和客戶(hù)端都是怎么設(shè)計(jì)的。

??????? 1 客戶(hù)端。客戶(hù)端由兩個(gè)方面組成:接收客戶(hù)輸入并把消息發(fā)送給服務(wù)器 和 接收由服務(wù)器發(fā)送給客戶(hù)端的消息。還是一樣,繼續(xù)分解問(wèn)題:先考慮接收客戶(hù)輸入并把消息發(fā)送給服務(wù)器怎么做?接受客戶(hù)輸入:可以用cin的getline接收,并把消息放到一個(gè)隊(duì)列里;把消息發(fā)送給服務(wù)器:借助c++asio網(wǎng)絡(luò)提供的api即可。再來(lái)看服務(wù)器發(fā)送給客戶(hù)端的消息怎么做?服務(wù)器發(fā)送給客戶(hù)端的數(shù)據(jù)通過(guò)網(wǎng)絡(luò)傳輸最開(kāi)始肯定是發(fā)到網(wǎng)卡上,但是對(duì)網(wǎng)卡的操作也太底層了,因此借助c++asio網(wǎng)絡(luò)庫(kù)——借助asio網(wǎng)絡(luò)庫(kù)的api接收服務(wù)端信息,并用隊(duì)列放到內(nèi)存,并用cout輸出即可。即:

  • 接收客戶(hù)輸入并把消息發(fā)送給服務(wù)器:用cin的getline接收用戶(hù)輸入,并把消息放到一個(gè)隊(duì)列里,最后用asio庫(kù)api發(fā)給服務(wù)器;
  • 接收由服務(wù)器發(fā)送給客戶(hù)端的消息:借助asio網(wǎng)絡(luò)庫(kù)的api接收服務(wù)端信息,并用隊(duì)列放到內(nèi)存,并用cout輸出。

??????? 2 服務(wù)器。服務(wù)器也是由兩個(gè)部分組成:接收客戶(hù)端消息 和 將聊天室消息發(fā)送給客戶(hù)端。因?yàn)楹涂蛻?hù)端有點(diǎn)類(lèi)似,這里直接給出結(jié)論,即:

  • 接收客戶(hù)端消息:通過(guò)asio網(wǎng)絡(luò)庫(kù)api接收客戶(hù)端消息,并把所有消息都放到一個(gè)隊(duì)列里,;
  • 將聊天室消息發(fā)送給客戶(hù)端:將隊(duì)列中的內(nèi)容借助asio網(wǎng)絡(luò)庫(kù)的api廣播(發(fā)送)給所有客戶(hù)端。

????? 3 數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)(細(xì)節(jié)設(shè)計(jì))

???????上面的設(shè)計(jì)內(nèi)容部分算是結(jié)束了,但具體如何去設(shè)計(jì)類(lèi)和數(shù)據(jù)結(jié)構(gòu)還有待商榷。

???????(1)分析消息協(xié)議部分

???????還是一樣,將分治的思想融入進(jìn)來(lái),無(wú)論是客戶(hù)端還是服務(wù)器,最先要解決的,就是雙方要統(tǒng)一消息的格式,也就是我們常說(shuō)的協(xié)議

???????因此我們?cè)O(shè)計(jì)一個(gè)chat_message類(lèi),用于存放消息,同時(shí)規(guī)定:消息結(jié)構(gòu)是 消息頭部 + 消息體的形式。消息頭部存放了消息體的長(zhǎng)度消息類(lèi)型(比如是客戶(hù)端發(fā)送給服務(wù)器聊天的消息還是服務(wù)器發(fā)給客戶(hù)端的消息),而且是定長(zhǎng)的,這樣就可以通過(guò)頭部去處理消息體的內(nèi)容。
簡(jiǎn)單表示一下就是:

struct Header{int bodySize;int type; }; enum MessageType {MT_BIND_NAME = 1,MT_CHAT_INFO = 2,MT_ROOM_INFO = 3, }; class chat_message {Header m_header;char data[header_length + max_body_length]; };

???????(2)分析客戶(hù)端

???????之后分析客戶(hù)端,cin的getline接收用戶(hù)輸入,同時(shí)還要有一個(gè)隊(duì)列,簡(jiǎn)單表示就是:

while (std::cin.getline(line, chat_message::max_body_length + 1)){chat_message msg;auto type = 0;std::string input(line, line + std::strlen(line));std::string output;if(parseMessage(input,&type,output)){msg.setMessage(type, output.data(), output.size());c.write(msg); }

下面是chat_client的表示:

chat_client {chat_message read_msg_;chat_message_queue write_msgs_; };

再分析一下要有什么函數(shù):
1 要有和服務(wù)器連接的函數(shù)——目前放在構(gòu)造函數(shù)里面。
2 要有接收函數(shù)——接收服務(wù)器發(fā)送的數(shù)據(jù)。
3 要有寫(xiě)出函數(shù)——向服務(wù)器發(fā)送自己的消息。

因此類(lèi)可以表示為:

chat_client { public://連接函數(shù)和接受函數(shù)都在構(gòu)造函數(shù)里面了//即chat_client(xxx) <==> connect + acceptchat_client(xxx); //有參構(gòu)造函數(shù)void write(const chat_message& msg); void close(); private:chat_message read_msg_;chat_message_queue write_msgs_; };

???????(3)分析服務(wù)器

???????服務(wù)器除了要和客戶(hù)端連接chat_server,還要有一個(gè)聊天室chat_room接收消息,但是在廣播消息的時(shí)候,需要向每個(gè)客戶(hù)端都發(fā)消息,因此用chat_session表示接入進(jìn)來(lái)的客戶(hù)端,簡(jiǎn)單表示如下:

class chat_room{private:chat_message_queue recent_msgs_; }; class chat_session {private:chat_room& room_; //屬于哪個(gè)聊天室std::string m_name; //這里是這個(gè)session的名字chat_message read_msg_;chat_message_queue write_msgs_; }; class chat_server{public://有參構(gòu)造函數(shù)里包括了connect和readchat_server(xxx);private:chat_room room_; //管理所有的room };

再分析一下需要有什么樣的函數(shù):
1 對(duì)于room來(lái)說(shuō),需要有客戶(hù)端加入到聊天室的join函數(shù)、需要有客戶(hù)端離開(kāi)的leave函數(shù)和向所有客戶(hù)端廣播的deliver函數(shù)。
2 所有的具體處理函數(shù)放在chat_session中,server只負(fù)責(zé)connect和read、room負(fù)責(zé)控制客戶(hù)加入退出和發(fā)送。到這其實(shí)已經(jīng)足夠,但為了封裝和可擴(kuò)展性,把server的read和room的發(fā)送放在了session里面做。即 read <=> session.start, deliver <=> session.deliver。

更完整的類(lèi)聲明如下:

class chat_room{public:void join(chat_session_ptr);void leave(chat_session_ptr);void deliver(const chat_message&);private:chat_message_queue recent_msgs_; }; class chat_session {public:void start();void deliver(const chat_message& msg);private:chat_room& room_; //屬于哪個(gè)聊天室std::string m_name; //這里是這個(gè)session的名字chat_message read_msg_;chat_message_queue write_msgs_; }; class chat_server{public://有參構(gòu)造函數(shù)里包括了connect和readchat_server(xxx);private:chat_room room_; //管理所有的room };

當(dāng)然,因?yàn)橐Y(jié)合c++的asio庫(kù),所以聲明肯定還要更復(fù)雜一些,但那都是asio的東西,把握了這主體的東西對(duì)我們的編程來(lái)說(shuō)就足夠了。

聊天室1.0

下面來(lái)看看聊天室1.0的內(nèi)容:

一共分為5個(gè)文件:
??????? 1 chat_message.hpp、structHeader.h、structHeader.cpp用于存放消息格式的約定(協(xié)議)。
??????? 2 chat_server.cpp放服務(wù)器相關(guān)邏輯。
??????? 3 chat_client.cpp放客戶(hù)端相關(guān)邏輯。

(為了文件少一點(diǎn),也可以把structHeader的內(nèi)容合到chat_message.hpp里面)
至此完成的就是asio的例子程序完成的內(nèi)容。不過(guò)雖然功能一樣,但是我們把消息變成了type進(jìn)行了一個(gè)小改動(dòng),這樣讓我們的可擴(kuò)展性就提升了一些,我們?cè)诖嘶A(chǔ)上加入客戶(hù)端可以發(fā)送“綁定名字”的消息。

運(yùn)行效果

??????? 在代碼解析之前,先跑起來(lái),看一下運(yùn)行效果,爽一下。這樣后續(xù)對(duì)代碼的理解也會(huì)更容易一些。(windows上應(yīng)該也能跑,用的都是跨平臺(tái)的庫(kù),因?yàn)閣indows上用visual stdio比較easy,這里在linux上跑一下)

??????? 編譯:

g++ -std=c++14 -pthread -I./ -L./ chat_client.cpp structHeader.cpp chat_message.hpp -o client g++ -std=c++14 -pthread -I./ -L./ chat_server.cpp structHeader.cpp chat_message.hpp -o server

??????? 編譯完以后是如下的效果:
??????? 之后先運(yùn)行server服務(wù)端

./server 9999

??????? 后面這個(gè)是端口號(hào),隨便給個(gè)正數(shù)即可。

??????? 之后再開(kāi)幾個(gè)客戶(hù)端,運(yùn)行客戶(hù)端

./client localhost 9999

之后在客戶(hù)端輸入
BindName 要輸入的名字
或者
Chat 聊天內(nèi)容

??????? 即可發(fā)送消息給服務(wù)器,服務(wù)器會(huì)廣播給所有的客戶(hù)端,同時(shí)當(dāng)有新客戶(hù)端加入進(jìn)來(lái)的時(shí)候,服務(wù)器會(huì)將最近的100條消息發(fā)給這個(gè)新加進(jìn)來(lái)的客戶(hù)端(即接收歷史信息)。
效果如下:

BindName或者Chat發(fā)送要發(fā)送消息的類(lèi)型(可以支持中文)

??????? 當(dāng)然,這個(gè)可以使用BindName直接Chat,這里只是簡(jiǎn)單展示。
??????? 當(dāng)客戶(hù)端退出時(shí)(ctrl+d推出,不要ctrl+c太暴力了)(windows應(yīng)該是ctrl+z,就是結(jié)束getline輸入的命令),服務(wù)器會(huì)顯示客戶(hù)端退出的消息。當(dāng)客戶(hù)端再次連接時(shí),會(huì)看到歷史消息

(visual多香,直接構(gòu)建項(xiàng)目搞定了)

聊天室1.0代碼簡(jiǎn)析(具體分析會(huì)在聊天室1.2的版本里)

??????? 關(guān)于頭文件的解析已經(jīng)在上面提過(guò)了,若是有所遺忘可以往上翻一下。
??????? 直接開(kāi)始具體介紹客戶(hù)端吧:
??????? 客戶(hù)端的主要函數(shù)和大致結(jié)構(gòu)在上面也已經(jīng)提過(guò),現(xiàn)在就是在之前提到的骨架上進(jìn)行“血肉填充”。

客戶(hù)端

1、連接+讀服務(wù)器數(shù)據(jù)

??????? 先看看構(gòu)造函數(shù):在客戶(hù)端構(gòu)造的時(shí)候就會(huì)進(jìn)行與服務(wù)器的連接建立,如果不希望這么做,可以把連接接口暴露出去,讓客戶(hù)端決定到底什么時(shí)候連接,這里為了簡(jiǎn)便就在構(gòu)造的時(shí)候連接了。

chat_client(boost::asio::io_context& io_context,const tcp::resolver::results_type& endpoints): io_context_(io_context),socket_(io_context){ do_connect(endpoints);}

??????? 看看do_connect怎么做的:

void do_connect(const tcp::resolver::results_type& endpoints){boost::asio::async_connect(socket_, endpoints,[this](boost::system::error_code ec, tcp::endpoint){ //回調(diào)函數(shù)if (!ec){do_read_header();}}); }

??????? 這里為什么要用異步呢?可以在連接的時(shí)候,在后臺(tái)準(zhǔn)備好和服務(wù)器對(duì)接的東西,比如游戲客戶(hù)端(LOL),要提前準(zhǔn)備圖形渲染、聲卡之類(lèi)的,就比較方便,然后這里調(diào)用了一個(gè)簡(jiǎn)單的回調(diào)函數(shù)。

??????? 簡(jiǎn)單點(diǎn)說(shuō),就是連接建立之后,服務(wù)器后面往客戶(hù)端發(fā)的消息就是要接收的消息了,解析消息的函數(shù)放在了do_read_header();里。
??????? 再來(lái)看看do_read_header()這個(gè)函數(shù):

void do_read_header(){boost::asio::async_read(socket_,boost::asio::buffer(read_msg_.data(), chat_message::header_length),[this](boost::system::error_code ec, std::size_t /*length*/){if (!ec && read_msg_.decode_header()){do_read_body();}else{ socket_.close();}});}

??????? 調(diào)用了asio的異步讀(簡(jiǎn)單點(diǎn)理解就是:服務(wù)器通過(guò)網(wǎng)絡(luò)把數(shù)據(jù)發(fā)到了客戶(hù)端的網(wǎng)卡上面,然后客戶(hù)端從網(wǎng)卡上讀取服務(wù)器發(fā)送的消息。)
??????? 異步的方式是:在數(shù)據(jù)來(lái)之前,我這個(gè)線(xiàn)程或者進(jìn)程可以去干別的事情,等數(shù)據(jù)來(lái)了,你網(wǎng)卡告訴我,我再拷貝到內(nèi)存里面去。就相當(dāng)于你在等飛機(jī)或者火車(chē)的中間喝咖啡看電影一樣。
??????? 拿到數(shù)據(jù)之后,解析頭部,如果頭部合法,就讀數(shù)據(jù)包體。(我得通過(guò)頭部長(zhǎng)度來(lái)知道后面多少數(shù)據(jù)是屬于我這個(gè)數(shù)據(jù)包的)

??????? 繼續(xù)看do_read_body()

void do_read_body(){boost::asio::async_read(socket_,boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),[this](boost::system::error_code ec, std::size_t /*length*/){if (!ec){//真正邏輯部分:判斷消息類(lèi)型if(read_msg_.body_length() == sizeof(RoomInformation) &&read_msg_.type() == MT_ROOM_INFO) {const RoomInformation *info =reinterpret_cast<const RoomInformation*>(read_msg_.body());std::cout << "client: '";assert(info->name.nameLen <= sizeof(info->name.name));std::cout.write(info->name.name, info->name.nameLen); std::cout << " says : '";assert(info->chat.infoLen <= sizeof(info->chat.information));std::cout.write(info->chat.information, info->chat.infoLen);std::cout << std::endl;}//循環(huán)讀包體,因?yàn)槭钱惒降?#xff0c;不會(huì)阻塞。(不會(huì)一直等著)do_read_header();}else{socket_.close();}});}

??????? 邏輯真的很簡(jiǎn)單:異步讀——>分析數(shù)據(jù)類(lèi)型——>循環(huán)讀包頭

2、向服務(wù)器寫(xiě)數(shù)據(jù)

??????? 寫(xiě)數(shù)據(jù)這個(gè)過(guò)程真的也很簡(jiǎn)單:從標(biāo)準(zhǔn)輸入讀(讀用戶(hù)輸入)——>解析輸入(是bindname還是chat還是非法)——>封裝成chat_message發(fā)出去

char line[chat_message::max_body_length + 1];while (std::cin.getline(line, chat_message::max_body_length + 1)){chat_message msg;auto type = 0;//這里有點(diǎn)像迭代器,獲得line的輸入std::string input(line, line + std::strlen(line));std::string output;//都封裝到這個(gè)parseMessage里面,整個(gè)框架就可以復(fù)用了if(parseMessage(input,&type,output)){msg.setMessage(type, output.data(), output.size());c.write(msg);std::cout << "write message for server " << output.size() << std::endl;}}

??????? 解析parseMessage和封裝setMessage非常簡(jiǎn)單,這里不過(guò)多說(shuō)明。這里封裝成一個(gè)函數(shù),增加了可復(fù)用性——當(dāng)解析邏輯改變時(shí),不用改變主邏輯結(jié)構(gòu)

??????? 主要看看write這個(gè)函數(shù)是怎么做的吧:

void write(const chat_message& msg){ boost::asio::post(io_context_,[this, msg]() //這里msg是值拷貝,而不是值引用{ //這里和chat message中的deliver處理是一樣的bool write_in_progress = !write_msgs_.empty();write_msgs_.push_back(msg);//只有write_msgs_是空的時(shí)候才進(jìn)行do_write,防止調(diào)用兩次do_writeif (!write_in_progress){do_write();}});}

??????? post可以簡(jiǎn)單理解創(chuàng)建了一個(gè)事件,用post就可以交給io_context_去管理,當(dāng)然這不是特別主要,主要來(lái)分析一下它的具體實(shí)現(xiàn):
??????? 將消息插入到發(fā)送隊(duì)列的尾部,并調(diào)用do_write()函數(shù)進(jìn)行發(fā)送。

??????? 看看do_write:

void do_write(){boost::asio::async_write(socket_,boost::asio::buffer(write_msgs_.front().data(),write_msgs_.front().length()),[this](boost::system::error_code ec, std::size_t /*length*/){if (!ec){write_msgs_.pop_front();//沒(méi)寫(xiě)完就繼續(xù)寫(xiě)if (!write_msgs_.empty()){do_write();}}else{socket_.close();}});}

??????? 是不是覺(jué)得很眼熟,簡(jiǎn)直和do_read_header如出一轍,不過(guò)他們的思想的確殊途同歸。
??????? 也是一樣:異步寫(xiě)——>將數(shù)據(jù)出隊(duì)列——>繼續(xù)回調(diào)do_write()

??????? 到這里,客戶(hù)端的讀寫(xiě)邏輯基本上都已經(jīng)說(shuō)完了,服務(wù)器的實(shí)現(xiàn)邏輯和客戶(hù)端真的也很像,我們也來(lái)簡(jiǎn)單分析一下。

服務(wù)器

1、接收客戶(hù)端消息

??????? 同樣,在構(gòu)造函數(shù)里和客戶(hù)端建立連接,同時(shí)接收來(lái)自客戶(hù)端的消息。

chat_server(boost::asio::io_context& io_context,const tcp::endpoint& endpoint): acceptor_(io_context, endpoint){do_accept();}

??????? 繼續(xù)看看do_accept:

void do_accept(){//這里異步連接一個(gè)新的客戶(hù)端acceptor_.async_accept([this](boost::system::error_code ec, tcp::socket socket){if (!ec){auto session = std::make_shared<chat_session>(std::move(socket), room_);session->start();}//這里可能會(huì)有錯(cuò)誤,但是服務(wù)器端的工作不能停//比如三次握手失敗了,失敗的邏輯在客戶(hù)端那邊處理,服務(wù)器不管,繼續(xù)監(jiān)聽(tīng)do_accept();});}

??????? 簡(jiǎn)單一看,異步連接+start,好家伙和客戶(hù)端邏輯長(zhǎng)的不說(shuō)一摸一樣也是有八分像了。
??????? 邏輯:async_accept異步連接——>創(chuàng)建session(一個(gè)客戶(hù)端可以理解成是一個(gè)session)——>開(kāi)始接收數(shù)據(jù)(start)——>回調(diào)自己(do_accept)。

???????繼續(xù)看看start函數(shù):

void start(){room_.join(shared_from_this());do_read_header(); //讀報(bào)文頭部}

???????加入到聊天室(為后面的寫(xiě)做鋪墊)+do_read_header。

???????一看到do_read_header懂得都懂,下一步肯定是do_read_body,直接看代碼吧:

void do_read_header(){//這里為了不被析構(gòu),所以搞了個(gè)這個(gè)內(nèi)容auto self(shared_from_this());//之后異步的去讀boost::asio::async_read(socket_,//把頭四個(gè)字節(jié)讀到buff里面去boost::asio::buffer(read_msg_.data(), chat_message::header_length),//第三個(gè)參數(shù)是一個(gè)函數(shù)指針,也就是一個(gè)回調(diào)函數(shù)[this, self](boost::system::error_code ec, std::size_t /*length*/){ //ec是error_code也就是模塊或者系統(tǒng)錯(cuò)誤,而且頭部信息合法//body長(zhǎng)度小于512if (!ec && read_msg_.decode_header()){do_read_body();}else{ //出錯(cuò)就斷開(kāi),這里智能指針引用計(jì)數(shù)為0room_.leave(shared_from_this());}});}

???????稍微解釋一下,這個(gè)auto self(shared_from_this());和智能指針的引用計(jì)數(shù)相關(guān),這里不多做解釋,后面會(huì)提到,感興趣的同學(xué)可以先看看。
???????同樣也是異步讀+do_read_body()。

void do_read_body(){//這里的目的和上面一樣auto self(shared_from_this());boost::asio::async_read(socket_,//也是一樣,把body的內(nèi)容讀到buff里面,錯(cuò)位了四個(gè)字節(jié)boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),[this, self](boost::system::error_code ec, std::size_t /*length*/){if (!ec){//handleMessage負(fù)責(zé)處理body里面的內(nèi)容,處理完以后繼續(xù)異步讀headerhandleMessage();do_read_header();}else{room_.leave(shared_from_this());}});}

2、向客戶(hù)端寫(xiě)

???????大家可能會(huì)疑惑:服務(wù)器往客戶(hù)端寫(xiě)的部分在哪里呢?
???????還記得前面有一步,客戶(hù)端會(huì)加入到聊天室。在join的時(shí)候,服務(wù)器就會(huì)根據(jù)room的內(nèi)容,對(duì)客戶(hù)端進(jìn)行寫(xiě)操作。

//chat_room函數(shù)實(shí)現(xiàn) void chat_room::join(chat_session_ptr session) {sessions_.insert(session);std::cout << "one client join the room" << std::endl;for (const auto& msg: recent_msgs_)session->deliver(msg); }

前面就是加入到聊天室隊(duì)列的邏輯,真正的寫(xiě)操作在deliver里:

void deliver(const chat_message& msg){bool write_in_progress = !write_msgs_.empty();write_msgs_.push_back(msg);//第一次為空,只有為空的時(shí)候才會(huì)調(diào)用do_write//這里是防止調(diào)用兩次do writeif (!write_in_progress){do_write();}}

大家看到do_write和客戶(hù)端的do_write一聯(lián)系,就很好理解了。

void do_write(){auto self(shared_from_this());boost::asio::async_write(socket_,boost::asio::buffer(write_msgs_.front().data(),write_msgs_.front().length()),[this, self](boost::system::error_code ec, std::size_t /*length*/){if (!ec){ //頭部信息寫(xiě)完了,就檢查是不是空的write_msgs_.pop_front();if (!write_msgs_.empty()){ //繼續(xù)寫(xiě)do_write();}}else{room_.leave(shared_from_this());}});}

到這里,整個(gè)客戶(hù)端——服務(wù)器 聊天室的主要邏輯功能相信大家都有了一個(gè)大體的認(rèn)識(shí),如果想繼續(xù)深入細(xì)節(jié),可以在github上把代碼下載下來(lái)自己動(dòng)手跑一下,在獲得樂(lè)趣的同時(shí)也可以加深對(duì)代碼的理解。

在后續(xù)的聊天室1.1和聊天室1.2中會(huì)詳細(xì)介紹里面的具體細(xì)節(jié)。

有趣的點(diǎn)

???????聊天室1.0里面比較有趣的點(diǎn)——也就是一開(kāi)始我比較疑惑的點(diǎn)主要就是在異步回調(diào)這里:
???????為什么要用auto self(shared_from_this);呢?
???????回調(diào)的時(shí)候?yàn)槭裁床粫?huì)出現(xiàn)爆棧呢?(因?yàn)轭?lèi)似循環(huán)調(diào)用)

異步循環(huán)調(diào)用為什么不爆棧?

???????要想弄清楚這幾個(gè)問(wèn)題,最先要解決的問(wèn)題就是——回調(diào)函數(shù)究竟是什么?
???????如果按照普通的函數(shù)調(diào)用過(guò)程進(jìn)行思考,每調(diào)用一次函數(shù),會(huì)將函數(shù)調(diào)用處壓棧空間,類(lèi)似下圖所示:(為了表示簡(jiǎn)單就直接用函數(shù)名字代替參數(shù)入棧什么的了)

???????我們以服務(wù)器接收客戶(hù)端消息為例:假如是在一個(gè)線(xiàn)程里面,用同步的思想去考慮,這樣不斷的循環(huán)調(diào)用肯定會(huì)出現(xiàn)爆棧的情況。
???????自然而然的我們會(huì)想到——系統(tǒng)級(jí)的異步,比如說(shuō)linux的epoll是怎么做的呢?交給內(nèi)核去管理,讓內(nèi)核進(jìn)行回調(diào)通知。如果抽象點(diǎn)看:把內(nèi)核看成另一個(gè)線(xiàn)程或者說(shuō)另一個(gè)工作場(chǎng)景,就像我現(xiàn)在遇到問(wèn)題了,找了一個(gè)朋友吧事情交給他做,然后我繼續(xù)做我接下來(lái)的事情。就好像這兩件事工作在不同的線(xiàn)程里面。
???????之后帶著自己的疑惑和自己的思考去請(qǐng)教了一下前輩們,雖然異步的實(shí)現(xiàn)方式遠(yuǎn)沒(méi)有我們想的那么簡(jiǎn)單,但是這種思想是貫穿始終的,為了簡(jiǎn)單起見(jiàn)——我們姑且認(rèn)為是在兩個(gè)線(xiàn)程里面工作的。(前輩說(shuō)具體實(shí)現(xiàn)要看future)

???????帶著這個(gè)思路我們就解決了爆棧的問(wèn)題——當(dāng)運(yùn)行到do_read_header的時(shí)候,start開(kāi)了個(gè)線(xiàn)程給了do_read_header,它自己就執(zhí)行完畢了,函數(shù)返回,自然也就不會(huì)存在爆棧的問(wèn)題。

為什么要使用self(shared_from_this)?

???????其實(shí)要搞清楚這個(gè)需要對(duì)智能指針比較熟悉,在此之前,我們把這個(gè)auto的一條語(yǔ)句給它展開(kāi),或許對(duì)它的理解會(huì)更容易一些。
??????? 還是以服務(wù)器接收客戶(hù)端消息為例:展開(kāi)整條賦值表達(dá)式就是:

std::shared_ptr<chat_session> self = shared_from_this();

??????? 這個(gè)shared_from_this簡(jiǎn)單理解就是智能指針管理的this指針。
??????? 看到這里可能大概明白了這條語(yǔ)句的意思:給這個(gè)對(duì)象(this指向的就是當(dāng)前session對(duì)象)增加一個(gè)引用計(jì)數(shù)。

??????? 但是為什么需要增加一個(gè)引用計(jì)數(shù)呢?
??????? 還記得上面說(shuō)的思想:當(dāng)成兩個(gè)線(xiàn)程去看。也就是說(shuō)當(dāng)do_read_header在運(yùn)行的時(shí)候,可能出現(xiàn)start已經(jīng)運(yùn)行結(jié)束的情況:

void do_accept(){acceptor_.async_accept([this](boost::system::error_code ec, tcp::socket socket){if (!ec){//這里是session的生命周期auto session = std::make_shared<chat_session>(std::move(socket), room_);session->start();} // start結(jié)束,這里智能指針的引用計(jì)數(shù)要減去1do_accept();});}void start(){room_.join(shared_from_this());do_read_header(); //用上面的思想:這條語(yǔ)句就是丟到另一個(gè)線(xiàn)程里去//丟完之后start就運(yùn)行結(jié)束了}

???????而start的結(jié)束就意味著do_accept里面的if也結(jié)束了,意味著session的引用計(jì)數(shù)要減去1,假如沒(méi)有別的指針持有這個(gè)對(duì)象,這個(gè)對(duì)象就會(huì)被釋放了。
???????所以還記得do_read_header里面是怎么做的了嗎?

void do_read_header(){//我覺(jué)得寫(xiě)auto還是有點(diǎn)憨批,本來(lái)就是強(qiáng)類(lèi)型語(yǔ)言//除非心里及其清楚這個(gè)auto代表著什么//std::shared_ptr<chat_session> self(shared_from_this());std::shared_ptr<chat_session> self = shared_from_this();boost::asio::async_read(socket_,boost::asio::buffer(read_msg_.data(), chat_message::header_length),//lambda表達(dá)式捕獲類(lèi)型是值捕獲[this, self](boost::system::error_code ec, std::size_t /*length*/){ //......});}

???????lambda表達(dá)式的捕獲是值捕獲,引用計(jì)數(shù)+1: 意味著async_read這個(gè)函數(shù)不結(jié)束,智能指針指向的這個(gè)session對(duì)象就不會(huì)釋放。保證了do_accept生成的chat_session的生命周期。

???????當(dāng)然為什么會(huì)出現(xiàn)這樣的疑惑主要還是因?yàn)閱尉€(xiàn)程的思想根深蒂固,只要日后多接觸多線(xiàn)程異步之類(lèi)的思想,習(xí)慣了以后就很容易理解了,這是個(gè)循序漸進(jìn)的過(guò)程,慢慢來(lái)就好。

聊天室1.0 github地址:

代碼很簡(jiǎn)單,完整代碼我把它放到了github上,后續(xù)我們會(huì)逐漸對(duì)他進(jìn)行更新和迭代,在循序漸進(jìn)中慢慢感受理論與實(shí)踐相結(jié)合的樂(lè)趣。
聊天室1.0

參考文獻(xiàn)

1 b站課程
2 boost-asio網(wǎng)絡(luò)庫(kù)

總結(jié)

以上是生活随笔為你收集整理的c++项目——聊天室——第一节的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

狠狠色噜噜狠狠 | 日韩在线免费电影 | 99热这里只有精品免费 | 国产手机视频在线 | 一区二区精品在线 | 99国产在线视频 | 国产免费作爱视频 | 99精品视频在线观看免费 | 丁香花在线视频观看免费 | 韩日电影在线免费看 | 亚洲 av网站 | 国产精品精品 | 亚州av免费 | 免费观看完整版无人区 | 精品91久久久久 | 久久精品中文字幕少妇 | 五月天色网站 | 日韩超碰在线 | 91九色性视频 | 久久综合久久久久88 | 夜夜爽天天爽 | 精品国产1区二区 | 深爱五月激情五月 | 天天操天天曰 | 成年人国产在线观看 | 国产色婷婷精品综合在线手机播放 | 二区视频在线观看 | 亚洲精品动漫成人3d无尽在线 | 国产一区二区在线影院 | 欧美大片在线看免费观看 | 99在线高清视频在线播放 | 麻豆免费精品视频 | 在线观看深夜视频 | 久草免费在线 | 国产精品中文久久久久久久 | 中文日韩在线视频 | 美女网站免费福利视频 | 免费av观看网站 | 99久久99久国产黄毛片 | 久久免费视频这里只有精品 | 国产成人av电影在线 | 成人黄色小说视频 | 久久免费视频4 | 精品国产诱惑 | 夜添久久精品亚洲国产精品 | 天天色天天骑天天射 | 日韩欧美精品一区二区 | 少妇bbbb搡bbbb桶 | 色吧久久 | 亚洲精品自拍视频在线观看 | 伊人黄色网 | 久草在线视频新 | 综合亚洲视频 | 日韩av免费一区二区 | 手机av资源 | 亚洲综合导航 | 国产精品99蜜臀久久不卡二区 | 国产精品成人av电影 | 麻豆传媒电影在线观看 | 国产手机在线观看 | av在线播放一区二区三区 | 激情综合网在线观看 | 欧美不卡在线 | 久久综合99 | 成年人免费在线观看网站 | 91精品入口| 国产精品成人一区二区三区吃奶 | 久久综合影院 | 亚洲欧美视频网站 | 中国一级片在线播放 | 正在播放 国产精品 | 久久久久久欧美二区电影网 | 亚洲视频2 | 久久久久欠精品国产毛片国产毛生 | 久久国内视频 | 精品人人人人 | 免费在线中文字幕 | 久久午夜鲁丝片 | 天天操天天操天天爽 | 99久久精品久久久久久清纯 | 欧美日韩一区二区久久 | 黄色成人av| 天天射天天干 | 人人爽影院 | 亚洲一区二区三区在线看 | 欧美在线观看小视频 | 久久高清视频免费 | 中文字幕三区 | 欧美a级成人淫片免费看 | 欧美日韩中文字幕在线视频 | 波多野结衣理论片 | 美女一区网站 | 日韩69av | 国产人免费人成免费视频 | 久久免费a| 欧美久久久久久久久中文字幕 | 亚州国产精品视频 | 免费看的黄网站 | 国产精品入口a级 | 日韩和的一区二在线 | 国产一级电影网 | 五月婷婷黄色网 | 国产色视频网站2 | 国产精品入口久久 | 中中文字幕av | 五月婷婷激情五月 | 五月天婷婷免费视频 | 成年人免费电影在线观看 | 日韩免费观看一区二区 | 免费看wwwwwwwwwww的视频 久久久久久99精品 91中文字幕视频 | 在线精品视频免费播放 | 高清日韩一区二区 | 欧美极品在线播放 | 蜜臀aⅴ国产精品久久久国产 | 国产一区二区精品久久91 | 欧美精品久久久久久久久久丰满 | 天天操天天操天天 | 五月婷婷六月丁香 | 天天综合区 | 亚洲黄色在线观看 | 国产高清福利在线 | 成年人视频免费在线播放 | 在线看中文字幕 | 国色天香在线观看 | 成年人免费观看国产 | 麻花豆传媒一二三产区 | 国产精品都在这里 | 亚洲国产操 | 激情文学综合丁香 | 成人黄色免费观看 | av中文字幕电影 | www178ccom视频在线| 精品欧美乱码久久久久久 | 色综合久久久久久中文网 | 国产精品久久久久久久电影 | 久久久国产一区 | 久久精品久久久久电影 | 亚洲理论在线观看电影 | 欧美日韩调教 | 色偷偷中文字幕 | 在线成人中文字幕 | 天天看天天干 | 丁香5月婷婷 | 91人人揉日日捏人人看 | 亚洲一区二区三区在线看 | 在线免费视频一区 | 久精品在线 | 日本在线视频一区二区三区 | 狠狠色丁香久久婷婷综合_中 | 精品久久国产精品 | 日日夜夜精品视频天天综合网 | 久草在线视频网站 | 久久人人看 | 91亚洲国产成人久久精品网站 | 天天综合成人 | 日韩三级视频 | 国产精品9区 | 二区三区在线观看 | 国产一线二线三线在线观看 | 国产在线最新 | 日韩久久精品一区 | 亚洲第一久久久 | 国产在线资源 | 伊人婷婷综合 | 色窝资源| 最新不卡av | 免费在线h| 九九九热精品 | 日韩视频免费 | 国产成人在线免费观看 | 久久专区| 国产成人精品三级 | 人人要人人澡人人爽人人dvd | a级黄色片视频 | 日韩av黄 | 国产网红在线 | 中文字幕第一页在线播放 | 网站在线观看你们懂的 | 日韩一区二区免费视频 | 天天爱天天操天天爽 | 99久久99久久综合 | 成年人在线播放视频 | 免费在线电影网址大全 | 一区久久久 | 91在线小视频 | 婷婷色在线资源 | www色,com | 日韩成年视频 | 免费国产一区二区视频 | 欧美另类69| 精品久久一级片 | 99在线精品免费视频九九视 | 久久久久久久99 | 免费看成人a| 99热精品久久 | 国产精品美女久久久免费 | 久久精品婷婷 | 狠狠色噜噜狠狠狠狠2021天天 | 国产亚洲精品bv在线观看 | 97在线播放视频 | 国产在线观看,日本 | 国产精品 中文在线 | 激情视频网页 | 色欧美日韩 | 午夜av免费 | 国产伦精品一区二区三区免费 | 日本黄色免费大片 | 国产一区二区中文字幕 | 国产一区二区在线看 | www五月婷婷 | 国产日韩精品在线 | 午夜少妇一区二区三区 | 日韩视频免费观看高清完整版在线 | 九九久久婷婷 | 国产 日韩 欧美 自拍 | 欧美另类重口 | 六月婷色 | 久久人人爽av| 天天爽天天摸 | 美女网站色免费 | 91人人澡人人爽 | 天天操天天操天天干 | 国产一二区在线观看 | 欧美一二区视频 | 综合色亚洲 | 在线日韩视频 | 午夜视频免费 | 亚洲va天堂va欧美ⅴa在线 | 99精品久久精品一区二区 | 天天色天天射天天综合网 | 天天草天天插 | 欧美激情视频一区 | 免费观看的黄色片 | 天天插狠狠干 | 日韩高清精品一区二区 | 99看视频在线观看 | 激情综合色综合久久 | 色婷婷电影 | 精品视频免费久久久看 | 久久精品www人人爽人人 | 久久精品a| 久久综合给合久久狠狠色 | 国产视频一区二区三区在线 | 一区二区不卡视频在线观看 | 超碰在线亚洲 | 天天天干天天射天天天操 | 日韩中文在线字幕 | 午夜精品一区二区三区在线观看 | wwwwww色| 国产成人免费在线 | 久久99精品久久只有精品 | 欧洲精品久久久久毛片完整版 | 91中文字幕在线播放 | 天天爱av导航 | 99精品视频网 | 免费三级av| 欧美91精品久久久久国产性生爱 | 亚洲久草网 | 在线免费中文字幕 | 免费看成人av | 中文字幕在线视频一区 | 亚洲精品美女久久久久网站 | 中文免费在线观看 | 丁香婷婷激情网 | 九九热免费视频在线观看 | 中文字幕一区二区在线播放 | 日韩免费电影网站 | 日韩毛片精品 | 国产精品美 | 综合久久久久久久 | 中文字幕在 | 91视频啪| 精品国产_亚洲人成在线 | 五月天久久久久久 | 欧美日韩国产页 | 日韩欧三级 | 国产精品一区二区果冻传媒 | 天堂av在线7| 亚洲三级在线免费观看 | 国产在线久久久 | 97视频资源 | 日韩欧美国产视频 | 有码一区二区三区 | 婷婷激情综合网 | 国产精品原创av片国产免费 | 综合天天久久 | 久久精品国产一区二区电影 | 1024手机在线看 | 久久天天操 | 五月天色站 | 在线精品亚洲 | 九九九热 | 欧美三级在线播放 | 天天射天天干天天操 | 久久久免费看视频 | 天天综合久久综合 | 天天夜夜操 | 天天射天天干天天插 | 天天色棕合合合合合合 | 99精品免费久久久久久日本 | 女人18毛片a级毛片一区二区 | 二区三区av | 久久久久久久久久久免费av | av色综合 | 最近日本韩国中文字幕 | 涩涩在线| 91欧美日韩国产 | 在线精品视频免费播放 | 日日夜夜精品免费观看 | 中文字幕在线国产精品 | 天天综合色天天综合 | 高清日韩一区二区 | 欧美日韩免费观看一区二区三区 | 久久草视频 | 亚洲视频在线看 | 在线成人中文字幕 | 狠狠的干 | 一本—道久久a久久精品蜜桃 | 久久网页 | 黄在线免费看 | 中文字幕日本电影 | 国产亚洲字幕 | 国产 在线 高清 精品 | 国产日产高清dvd碟片 | 欧美一级xxxx | 国产精品久一 | 欧美日韩一区二区三区不卡 | 国产99久久99热这里精品5 | 日韩电影精品一区 | 久久a v视频 | av先锋影音少妇 | 中文字幕av免费观看 | 一级淫片在线观看 | www最近高清中文国语在线观看 | 亚洲一区久久久 | 天天看天天干 | 国产一二三精品 | 亚州精品成人 | 中文字幕一区二区三区四区视频 | 色综合久久五月天 | 国产成人精品不卡 | 免费在线一区二区三区 | 91片黄在线观看动漫 | 日韩精品2区 | 九九热精品国产 | 亚洲国产最新 | 九九免费精品视频在线观看 | 色网站在线 | 天天操夜夜看 | 久草久草视频 | 国产精品久久久一区二区 | 精品国产乱码 | 国产三级精品三级在线观看 | 欧美日韩在线观看不卡 | 九九热在线观看 | 日韩国产精品毛片 | 欧美a级在线免费观看 | 国产中文在线视频 | 国产免费黄视频在线观看 | 久久精品艹 | 久久精品成人欧美大片古装 | 久久精品视频国产 | 亚洲精品影院在线观看 | 日韩高清免费在线观看 | 色99在线| 色婷婷综合久久久久中文字幕1 | 免费高清无人区完整版 | 久久久久久久久久久福利 | 日韩草比| 蜜臀aⅴ精品一区二区三区 久久视屏网 | 国产精品毛片一区二区在线看 | a久久免费视频 | 中文字幕一区二区三区四区在线视频 | 97免费 | 不卡视频一区二区三区 | 97在线视频免费看 | 日韩美一区二区三区 | 久久黄色影视 | 色狠狠干 | 日韩亚洲在线视频 | av在线播放一区二区三区 | 99久久日韩精品免费热麻豆美女 | 国产97在线看 | 欧美激情精品久久久久久 | 91中文字幕网 | 日韩av电影一区 | 丁香 婷婷 激情 | 精品美女久久 | 国产91精品看黄网站在线观看动漫 | 视频国产在线 | 夜夜躁日日躁狠狠躁 | 91精品国产欧美一区二区成人 | 久久高清国产视频 | 13日本xxxxxⅹxxx20 | 成人欧美一区二区三区在线观看 | 国产精品第十页 | 久久免费精品视频 | 97超碰免费在线观看 | 99久久婷婷国产综合亚洲 | 日韩一级网站 | 成人综合婷婷国产精品久久免费 | 午夜精品久久久久久中宇69 | 国产精品网在线观看 | 色综合天天爱 | 六月丁香久久 | 黄色的网站免费看 | 丁香花在线视频观看免费 | 欧美视频国产视频 | 免费在线观看污网站 | 九九热精品视频在线播放 | 又黄又爽又无遮挡的视频 | 高清中文字幕 | 国产在线播放一区 | 香蕉久久国产 | 国产二区电影 | 免费观看一区二区 | 天天干天天干天天 | 在线观看国产一区二区 | 久久久久区 | 99在线精品免费视频九九视 | 黄色av网站在线观看 | 在线看片中文字幕 | 五月婷婷久久丁香 | 91探花视频 | 国产福利在线免费 | 日韩一级片大全 | 国产精品美女www爽爽爽视频 | 成人91在线 | 精品不卡av | 色多多视频在线观看 | 精品麻豆 | 国产在线高清视频 | 国产成人精品一区二区三区网站观看 | 九九九毛片 | 日韩高清二区 | 成人国产精品久久久久久亚洲 | 久久国产品 | 午夜久久精品 | 欧美一级专区免费大片 | 一级黄色av | 亚洲涩综合 | 91麻豆精品国产午夜天堂 | 日日夜夜中文字幕 | 黄色日本免费 | 欧美视频xxx | 国产精品欧美一区二区三区不卡 | 久久99精品热在线观看 | 91cn国产在线 | 久久久久久蜜av免费网站 | 日韩乱理 | 我要色综合天天 | 天天射天天射 | 18国产精品白浆在线观看免费 | 日韩99热 | 99热在线这里只有精品 | 久久伊人热 | 9999国产精品| 国产 欧美 日本 | 国产一区二区三区黄 | 久久久国产精品亚洲一区 | 久久久18 | a特级毛片 | 婷香五月| 日韩精品一区二区三区水蜜桃 | 国产不卡在线看 | 国产精品久久久久久久久免费看 | 日本中文在线播放 | 成人性生爱a∨ | 国产精品久久久久久久久免费看 | 国内精品久久久久影院男同志 | 欧美日韩性生活 | 久久天堂精品视频 | 奇米四色影狠狠爱7777 | 亚洲极色 | 国产精品久久久亚洲 | 欧美日韩中文在线 | 伊人视频 | 黄网站app在线观看免费视频 | 国产五十路毛片 | 国产亚洲永久域名 | 99精品欧美一区二区 | 波多野结衣一区三区 | 欧美精品一区二区三区四区在线 | 国产精品1区2区3区在线观看 | 亚洲精品小视频在线观看 | 久久久久久电影 | 国产精品理论片 | 亚洲精品2区| 国产亚洲精品久久久久久大师 | 国内精品久久久久久久久久久 | 黄色美女免费网站 | 成人久久久精品国产乱码一区二区 | 国产免费黄视频在线观看 | 人人看人人做人人澡 | 一级精品视频在线观看宜春院 | av成人资源| 深夜精品福利 | 亚洲涩涩网 | 国产精品美女999 | 国产黄色大片 | 亚洲欧美视频在线播放 | 在线观看视频国产一区 | 在线日韩| 国产手机视频在线观看 | 午夜美女视频 | 国产1区2区3区精品美女 | 国产一区在线视频播放 | 天天草天天干天天射 | 1024手机看片国产 | 精品一二三四视频 | 五月激情av | 国产精久久久久久久 | 一区二区视频欧美 | 亚洲日本在线一区 | 夜色在线资源 | 97人人澡人人爽人人模亚洲 | 五月激情丁香图片 | 国产99亚洲 | 少妇bbb| 国产亚洲一区二区在线观看 | 免费高清影视 | 又污又黄的网站 | 亚洲区精品 | 日韩免费看的电影 | 91精品国产成 | 天天射天天爱天天干 | 亚洲精品资源在线观看 | 国产精品久久久久久久久久三级 | 国产成人一级 | www.黄色小说.com | 一级淫片在线观看 | 开心激情综合网 | 在线观看成年人 | 伊人久久精品久久亚洲一区 | 国产r级在线观看 | av 在线观看 | 高清中文字幕av | 久久综合久久综合九色 | 国产精品影音先锋 | 久久一区二区三区超碰国产精品 | 人人看人人爱 | 色网av | 成人在线观看资源 | 国产aa精品 | 日韩视频一区二区三区在线播放免费观看 | 99久久精品久久久久久清纯 | 黄色91在线观看 | 看毛片的网址 | 日韩一区二区三区免费视频 | 久久草视频 | 国产成人精品亚洲 | 日韩av资源站| 日韩三级免费观看 | 九九精品在线观看 | 日韩免费福利 | 天天艹天天 | 9999亚洲 | 亚洲日本激情 | 国产亚洲va综合人人澡精品 | 中文在线免费看视频 | 婷婷亚洲综合五月天小说 | av免费看av| 中文字幕免费观看视频 | 欧美精品免费在线观看 | 国产精品欧美久久久久无广告 | 国产精品国产亚洲精品看不卡15 | 欧美精品中文在线免费观看 | 99爱国产精品 | 精品不卡视频 | 在线免费观看国产黄色 | 国内精品久久久久久久影视简单 | 又大又硬又黄又爽视频在线观看 | 欧美一区二区在线免费看 | 91精品在线免费 | 久久精品久久久精品美女 | 97碰碰视频 | 91麻豆传媒 | 在线电影av | 美女免费视频网站 | 在线成人短视频 | 国产在线播放观看 | 国产高清不卡在线 | 黄色毛片大全 | 久久婷婷一区 | 91夫妻视频 | 亚洲最新av在线网站 | 国产最新视频在线 | 国产高清成人av | 日日干夜夜草 | 一区二区三区四区五区在线视频 | 成人黄色免费观看 | 最新精品国产 | 99色精品视频 | 久久久www成人免费毛片 | 成人a视频 | 在线观看亚洲国产精品 | 特黄特色特刺激视频免费播放 | 亚洲国产精品人久久电影 | 中文字幕一区二区在线观看 | 在线看日韩av | 欧美午夜性生活 | 美女在线观看网站 | 天天操网站 | 亚洲欧美视频一区二区三区 | 国产一区在线视频播放 | 在线小视频你懂得 | 色视频在线看 | 黄网站免费看 | 91精品国产福利在线观看 | 亚洲va男人天堂 | 国产在线观看免费观看 | 天堂激情网 | 中文字幕第一 | 少妇18xxxx性xxxx片 | 精品国产亚洲一区二区麻豆 | 人人澡人人模 | 久久国产精品99国产 | 免费看国产视频 | 久久精品99| 久草视频免费在线观看 | 亚洲 欧洲 国产 日本 综合 | 国产91精品在线播放 | 五月天伊人网 | 久久天天躁狠狠躁夜夜不卡公司 | 日本高清中文字幕有码在线 | 天天操导航 | 国产视频精品免费播放 | 亚洲在线黄色 | 最近中文国产在线视频 | 毛片一区二区 | 182午夜在线观看 | 国产99免费| 在线视频免费观看 | 91亚洲精品久久久蜜桃网站 | 91av视频在线免费观看 | 九九在线免费视频 | 久久国产精品免费观看 | 免费在线观看av电影 | 久草在线免费资源站 | 婷婷深爱五月 | 日日爱影视 | 一区二区三区四区在线免费观看 | 日日夜夜人人精品 | 亚洲黄色一级大片 | 在线观看日本高清mv视频 | 国产男女爽爽爽免费视频 | 欧洲在线免费视频 | 在线a人片免费观看视频 | 毛片一二区 | 国产精品网红直播 | 国产人成看黄久久久久久久久 | 成人免费看片网址 | 国产手机视频在线播放 | 国产91粉嫩白浆在线观看 | 久久久久日本精品一区二区三区 | 日韩欧美视频免费看 | 成人禁用看黄a在线 | 欧美亚洲另类在线视频 | 在线看日韩av | 成人av动漫在线观看 | 久久久久北条麻妃免费看 | av 在线观看 | 天天av在线播放 | 久久婷婷精品视频 | 久久一区二区三区日韩 | 中文字幕在线成人 | 欧美激情亚洲综合 | 精品亚洲欧美一区 | 国产一区二区日本 | 伊人影院99 | 少妇高潮冒白浆 | 成人毛片久久 | 欧美一区二区三区特黄 | 中文字幕在线播放日韩 | 国产精品免费久久久久久久久久中文 | 久久精品草| 成人app在线播放 | 亚洲综合色视频 | 欧美性做爰猛烈叫床潮 | 99免费在线播放99久久免费 | 国产一区在线不卡 | 91手机电影| 二区视频在线 | 欧美一级专区免费大片 | 日韩va欧美va亚洲va久久 | 最新日韩精品 | 成人精品影视 | av免费在线免费观看 | 国产一级淫片免费看 | 国产69熟 | 91一区在线观看 | 久久91网| 成人免费观看电影 | 欧洲色吧| 999免费视频 | 97超碰中文| 国产资源网站 | 日本久久91| 免费观看十分钟 | 免费看的av片 | 色综合激情网 | av片在线看 | 久久激五月天综合精品 | 久久精品一级片 | 欧美人交a欧美精品 | 狠狠色丁香婷婷综合最新地址 | 久草在线电影网 | 麻豆视频在线观看 | 日韩女同一区二区三区在线观看 | 日韩在线欧美在线 | 午夜视频欧美 | 日日夜夜爱 | 中文字幕制服丝袜av久久 | 一二三四精品 | 一区二区三区视频 | 欧美a性 | 久久美女精品 | 久久精品4 | 国产精品观看视频 | 欧美成人精品欧美一级乱黄 | 91精品国| 麻豆久久久久久久 | 国产精品激情 | 国产精品午夜免费福利视频 | 日韩精品免费一线在线观看 | av成人免费| 日韩区欧美久久久无人区 | 在线免费观看涩涩 | 国产精品1区2区在线观看 | 青青草华人在线视频 | 在线播放91 | 精品嫩模福利一区二区蜜臀 | 狠狠干夜夜操天天爽 | 日韩一区二区三区视频在线 | 黄网站色欧美视频 | 97色婷婷 | 一区二区三区四区五区在线视频 | 亚洲精品视频在线免费 | 亚洲成年人在线播放 | www.亚洲精品在线 | 日韩免费在线观看视频 | 在线性视频日韩欧美 | 亚洲国产电影在线观看 | 久久伦理电影网 | 日韩在线观看视频在线 | 狠狠色狠狠色终合网 | 麻豆小视频在线观看 | 麻豆视频免费在线播放 | 久久国产一二区 | 日狠狠 | 91粉色视频| 在线av资源 | 91精品久久久久久粉嫩 | 国产亚洲精品久久19p | 国产成人久久av免费高清密臂 | 免费日韩 精品中文字幕视频在线 | 在线观看黄网站 | 五月开心色 | 久久久免费国产 | 欧美日韩高清在线一区 | 精品麻豆 | 狠狠色丁香婷婷综合橹88 | 国产精品免费久久久久影院仙踪林 | 欧美激情精品久久 | 久久久久久久久久久久国产精品 | 日韩高清在线观看 | 国产精品久久久久久久久久三级 | 日韩精品一区二区三区免费观看 | 亚洲激情中文 | 在线观看黄网 | 欧美视频一区二 | 色伊人网 | 久久精品久久99精品久久 | 欧美在线aa | 亚洲精品久久久久999中文字幕 | 午夜精品久久久久久久久久久久 | 成年人在线观看网站 | 右手影院亚洲欧美 | 在线观看蜜桃视频 | 亚洲国产日韩精品 | 国产性天天综合网 | 欧美大香线蕉线伊人久久 | 国产在线更新 | 狠狠躁夜夜躁人人爽超碰91 | 亚洲91视频| 日韩三区在线观看 | 青草视频在线 | 亚洲乱码一区 | 91伊人影院 | 色多多污污在线观看 | www免费视频com | 波多野结衣在线视频一区 | 国产打女人屁股调教97 | 国产精品久久av | 精精国产xxxx视频在线播放 | 欧美日韩69| 黄色免费高清视频 | 亚洲精品国产成人av在线 | 日韩一级黄色大片 | 国产精品久久久久久一区二区三区 | 婷婷六月色 | 久久精品高清 | 91免费版在线| 欧美日韩国产欧美 | 91少妇精拍在线播放 | 91大神一区二区三区 | 亚洲天堂免费视频 | 97超级碰碰碰碰久久久久 | 一级黄色电影网站 | 国产一区欧美一区 | 久久九九影视网 | 久久久av免费 | 看黄色.com | 黄视频色网站 | 日韩av网页 | 99视频播放| 成人h动漫精品一区二 | 久香蕉 | 国产 日韩 欧美 自拍 | 久久综合狠狠综合久久激情 | 91成年视频| 日韩av影视在线观看 | 在线观看岛国片 | 久久久免费网站 | 久久艹国产视频 | 黄色小视频在线观看免费 | 国产色拍| 亚洲涩涩一区 | 国产精品欧美日韩在线观看 | 久久久这里有精品 | 精品在线观看一区二区三区 | 91成年人在线观看 | 久久9999久久免费精品国产 | 激情综合五月婷婷 | 国产免费作爱视频 | 亚洲日本va午夜在线电影 | 日韩欧美精品在线视频 | 国产精品精品视频 | av天天草| 蜜臀aⅴ国产精品久久久国产 | 日韩亚洲在线观看 | 麻豆影音先锋 | 国产三级久久久 | 久草视频在线新免费 | 久久久久久久久影视 | 色综合久久综合网 | 免费高清看电视网站 | 中文乱码视频在线观看 | 一级免费黄视频 | 国产一级久久 | 久草在线一免费新视频 | 天堂视频一区 | 最近中文字幕大全中文字幕免费 | 激情婷婷 | 久久艹在线观看 | 国产亚洲久一区二区 | 黄色一级动作片 | 97av免费视频 | 中文免费在线观看 | 四虎影视成人永久免费观看视频 | 亚洲激情综合网 | 一区二区日韩av | 五月婷婷,六月丁香 | 国产视频1| 视频一区二区视频 | 久久免费的精品国产v∧ | 人人干网 | 激情欧美一区二区三区 | 中文字幕在线观看一区二区三区 | 亚洲黄色区 | 国产高清免费视频 | 中文在线字幕免 | 国产一级片在线播放 | 久99久在线 | 天天操天天怕 | 四虎国产精 | 一区二区三区高清 | 中文国产在线观看 | 欧美另类高清 videos | 一区二区三区在线视频观看58 | 久久精品国产精品亚洲 | 国产91精品久久久久久 | 黄色影院在线观看 | 亚洲欧美激情插 | av不卡中文字幕 | 国产精品美女免费看 | 国产精品第一视频 | 在线观看网站你懂的 | 日韩三级.com| 狠狠干狠狠色 | 国产精品手机在线播放 | 狠狠操狠狠干天天操 | 久久久久免费精品国产小说色大师 | 婷婷深爱| 一级α片免费看 | 国产中文字幕网 | 精品久久久久_ | 日韩大片在线观看 | 在线观看日韩视频 | 四虎国产精品成人免费4hu | 久久一级片 | 天天躁日日 | 五月婷婷在线观看视频 | 91精品伦理 | 亚洲精品久久久久久中文传媒 | 三级av免费 | 国产在线观看中文字幕 | 深爱综合网| 在线观看深夜福利 | 深爱婷婷久久综合 | 黄色大全免费观看 | 91精品色| 久久一区二区三区四区 | 成人四虎 | 91在线视频播放 | 日韩三区在线观看 | 手机成人av在线 | 婷婷色中文字幕 | 外国av网 | 婷婷色六月天 | 99热这里精品 | 免费看三级网站 | 免费观看视频的网站 | 黄色大片网 | 五月天电影免费在线观看一区 | 国产又粗又硬又长又爽的视频 | 成人全视频免费观看在线看 | 久久久久久免费毛片精品 | 色丁香综合 | 国精产品999国精产品岳 | 日韩免费电影一区二区 | 国产高清不卡一区二区三区 | 久久久久久久久久电影 | 国产精品国产亚洲精品看不卡 | 一级黄色网址 | 天天插夜夜操 | 九九久久久久久久久激情 | 日本久久久影视 | 久久永久视频 | 亚洲婷婷在线视频 | 国产精品一区二区麻豆 | 婷婷综合亚洲 | 亚洲一区二区三区毛片 | 亚洲日本va午夜在线影院 | 免费高清影视 | 国产在线久草 | 国产精品黄色影片导航在线观看 | 精品一区二区免费在线观看 | 欧美二区三区91 | 国产精品久久久av | 免费碰碰 | 最近日韩免费视频 | 日韩欧美一区二区不卡 | 成年人视频在线免费播放 | www免费视频com━ | 久久电影网站中文字幕 | 91视频高清 | 91九色老| 国产精品永久在线观看 | 日韩欧美大片免费观看 | 日本xxxx.com | 成人一级片在线观看 | 蜜臀av性久久久久av蜜臀妖精 | av性在线| 国产午夜精品av一区二区 | 国产一区二区在线观看视频 | www.eeuss影院av撸 | 日韩在线电影观看 | 欧美日韩性| 日韩在线观看高清 | 国产在线播放一区二区 | 国产精品中文字幕在线 | 国产一区私人高清影院 | 天天爽人人爽夜夜爽 | 久久久久色| 日日夜夜噜 | 狠狠狠狠狠干 | 在线观看日韩精品 | 久久久久免费网站 | 黄色资源网站 | 97精品国产91久久久久久久 | 在线色视频小说 | 色偷偷88欧美精品久久久 | 欧美激情视频在线观看免费 | 久久一级电影 | 在线国产不卡 | 99久久夜色精品国产亚洲96 | 国产九色视频在线观看 | 国产午夜精品一区二区三区嫩草 | 久久精品精品电影网 | 五月天综合婷婷 | 色www精品视频在线观看 | 国产免费观看视频 | 国产福利在线免费观看 | 久久亚洲综合国产精品99麻豆的功能介绍 | av中文字幕在线免费观看 | 韩国精品在线观看 | 日本韩国精品一区二区在线观看 |