• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            Creative Commons License
            本Blog采用 知識(shí)共享署名-非商業(yè)性使用-禁止演繹 3.0 Unported許可協(xié)議 進(jìn)行許可。 —— Fox <游戲人生>

            游戲人生

            游戲人生 != ( 人生 == 游戲 )
            站點(diǎn)遷移至:http://www.yulefox.com。請(qǐng)訂閱本博的朋友將RSS修改為http://feeds.feedburner.com/yulefox
            posts - 62, comments - 508, trackbacks - 0, articles - 7

            2010年1月7日

            本文同步自游戲人生

            最近有點(diǎn)忙,本來(lái)要用autoconf+automake把自己的代碼梳理一下的,因?yàn)楣ぷ魍A私鼉芍堋?/p>

            本想看看有什么工具可以自動(dòng)生成Makefile.am,答案是:Automake不支持通配符,而且還口口聲聲,振振有詞。既然說(shuō)的這么言詞鑿鑿,情深意切,我想我也沒(méi)有必要用shell生成Makefile.am了。

            用著用著,我有點(diǎn)懷疑人生了:不知道什么時(shí)候需要用autoconf和automake。如果我只是平時(shí)自己寫一些toy codes的話,感覺(jué)用autoconf和automake有點(diǎn)大炮打蚊子的感覺(jué),而且每次新加代碼或者是移除代碼、甚至是更改目錄,都要重新執(zhí)行 autoconf、automake(不知道我說(shuō)的對(duì)與不對(duì))。對(duì)于一個(gè)大型項(xiàng)目,執(zhí)行一次configure和make是很痛苦的一件事,make的中 間目標(biāo)文件或者庫(kù)文件、執(zhí)行文件倒是不一定非得完全rebuild,configure的配置檢查呢?是不是也有類似機(jī)制?反正我在用ogre或者 cegui的時(shí)候,每次執(zhí)行./configure是重新配置了的。

            實(shí)際在開(kāi)源項(xiàng)目里面也不可能維護(hù)兩套makefile吧。

            看了一下googletest的配置,倒是清爽的很,最大的特點(diǎn)是只有一個(gè)Makefile.am,這樣在一個(gè)項(xiàng)目里面只需要維護(hù)一個(gè)Makefile.am就夠了。

            cegui比較常規(guī),每個(gè)子目錄都會(huì)維護(hù)一個(gè)Makefile.am。

            需要特別注意的是ogre從1.7.0開(kāi)始已經(jīng)開(kāi)始使用cmake了……

            請(qǐng)聽(tīng)題:管理中小型項(xiàng)目,你傾向于下面哪個(gè)工具?

            o make:鉆木取火,玩的就是個(gè)技術(shù),編譯代碼,只用裝B的,不用牛B的,你要是用什么cmake,你都不好意思跟別人打招呼,這么經(jīng)典的東西,精通需要多久?要我說(shuō)怎么著也得個(gè)把倆月吧,個(gè)把倆月?那是入門,至少半年,就這還得有Feldman的悟性,不舍晝夜;

            o autoconf+automake:既有群眾基礎(chǔ),又有技術(shù)含量,你是那樣拉轟的男人,不管在什么地方,就好像漆黑中的螢火蟲(chóng)一樣,那樣的鮮明,那樣的 出眾。你那憂郁的眼神,稀噓的胡喳子,神乎其技的指法;既可以恥笑原始人的生產(chǎn)力低下,還可以鄙視現(xiàn)代人的不學(xué)無(wú)術(shù)。

            o cmake:在MSVCers面前抬不起頭,在UNIXers面前似乎更抬不起頭;而cmake對(duì)WINDOWS和UNIX平臺(tái)的完美支持,足以讓所有的 MSVCers和UNIXer在你面前抬不起頭,你是公雞中的戰(zhàn)斗機(jī)。所以你還是可以趾高氣昂的丟下一句:走NB的路,讓SB說(shuō)去吧。


            posted @ 2010-01-07 01:32 Fox 閱讀(3996) | 評(píng)論 (4)編輯 收藏

            2009年12月23日

                 摘要: 從接觸和使用make以來(lái),前前后后寫了不少M(fèi)akefile(添添減減、修修補(bǔ)補(bǔ),累計(jì)上千行是有的),今天在重新整理代碼的組織結(jié)構(gòu)之后,突然就想:我為什么不使用Autotools呢?

            在開(kāi)始體驗(yàn)功能強(qiáng)大的Autotools之前,簡(jiǎn)單(詳細(xì))回憶總結(jié)一下我使用make的經(jīng)歷和思考的過(guò)程,反省一下看看自己在接觸這些新鮮事物的時(shí)候到底走了多少?gòu)澛贰?nbsp; 閱讀全文

            posted @ 2009-12-23 02:18 Fox 閱讀(6921) | 評(píng)論 (5)編輯 收藏

            2009年12月6日

            本文同步自游戲人生

            Writen by Fox(yulefox.at.gmail.com)

            在具體討論之前,本文先厘清UUID(Universally Unique IDentifier)與GUID(Globally Unique IDentifier)的關(guān)系。

            在分布式、網(wǎng)絡(luò)、單機(jī)環(huán)境下,為了能夠使用具有某種形式的ID唯一標(biāo)識(shí)系統(tǒng)中的任一元素,這樣的ID可以不依賴中心認(rèn)證自動(dòng)生成,于是UUID就誕生了。

            UUID標(biāo)準(zhǔn)的歷史沿革和具體實(shí)現(xiàn)在RFC 4122ITU-T Rec. X.667ISO/IEC 9834-8:2008中均有詳細(xì)描述。ITU和ISO采用的標(biāo)準(zhǔn)和RFC 4122都是在UUID的早期版本基礎(chǔ)上完成,各版本之間具有一致性和兼容性。

            因?yàn)椴荒鼙WCUUID的唯一性,ITU和ISO針對(duì)UUID的使用都有免責(zé)聲明。

            GUID一般是指Microsoft對(duì)于UUID標(biāo)準(zhǔn)的實(shí)現(xiàn),UUID的實(shí)現(xiàn)則多見(jiàn)于其他系統(tǒng)(*NIX、MAC OS等)中。在了解了這一區(qū)別后,本文將統(tǒng)一使用UUID來(lái)指代對(duì)應(yīng)的原理、算法及實(shí)現(xiàn)。

            文中關(guān)于UUID的討論全部基于RFC 4122和ITU-T Rec. X.667以及OSF、IETF、ITU-T、ISO、FIPS的各種標(biāo)準(zhǔn)文檔。而UUID的細(xì)節(jié)(如結(jié)構(gòu)、表示、算法、實(shí)現(xiàn)等)均以ITU-T Rec. X667為唯一藍(lán)本,文中“本標(biāo)準(zhǔn)”即指代該藍(lán)本。

            o 介紹

            UUID是長(zhǎng)度為16-byte(128-bit)的ID,一般以形如f81d4fae-7dec-11d0-a765-00a0c91e6bf6的字符串作為URN(Uniform Resource Name,統(tǒng)一資源名稱)。

            o 動(dòng)機(jī)

            無(wú)須中心認(rèn)證,自動(dòng)生成,支持一臺(tái)機(jī)器每秒生成10M次(100納秒級(jí),其隱含原因是指能夠區(qū)分的最小時(shí)間單位為100ns,將時(shí)間作為因子時(shí),連續(xù)生成兩個(gè)UUID的時(shí)間至少要間隔100ns)。方便存取、分配、排序、查找。

            o 結(jié)構(gòu)


               76543210765432107654321076543210
               + – - – = – - – = – - – = – - – +
            15 |            TimeLow            | 12
            11 |    TimeMid    |   Version..   |  8
            7  |Vari.. |Clock..|     Node      |  4
            3  |             Node              |  0
               + – - – = – - – = – - – = – - – +
            15 – 12: TimeLow 時(shí)間值的低位
            11 – 10: TimeMid 時(shí)間值的中位
            09 – 08: VersionAndTimeHigh 4位版本號(hào)和時(shí)間值的高位
            07: VariantAndClockSeqHigh 2位變體(ITU-T)和時(shí)鐘序列高位
            06: ClockSeqLow 時(shí)鐘序列低位
            05 – 00: Node 結(jié)點(diǎn)
            hexOctet = hexDigit hexDigit
            hexDigit =
            “0″ / “1″ / “2″ / “3″ / “4″ / “5″ / “6″ / “7″ / “8″ / “9″ /
            “a” / “b” / “c” / “d” / “e” / “f” /
            “A” / “B” / “C” / “D” / “E” / “F”
            UUID =
            TimeLow
            “-” TimeMid
            “-” VersionAndTimeHigh
            “-” VariantAndClockSeqHigh ClockSeqLow
            “-” Node

            UUID由上述6個(gè)域構(gòu)成,每個(gè)域編碼為若干字節(jié),并以16進(jìn)制數(shù)表示這128位的UUID,相鄰域以減號(hào)“-”分隔 (VariantAndClockSeqHigh和ClockSeqLow對(duì)應(yīng)的兩個(gè)字節(jié)例外,如上所示)。該結(jié)構(gòu)中包含版本(Version)、變體 (Variant)、時(shí)間(Time)、時(shí)鐘序列(Clock Sequence)、節(jié)點(diǎn)(Note)信息(以無(wú)符號(hào)整型值表示)。

            o 合法性

            除判斷variant位設(shè)置是否正確、基于時(shí)間生成的UUID時(shí)間值是否為未經(jīng)分配的將來(lái)時(shí)間外,實(shí)際應(yīng)用中沒(méi)有其他機(jī)制可以判定UUID是否合法。

            o 變體

            Variant位是UUID第7字節(jié)(VariantAndClockSeqHigh)的最高3位,

            7 6 5  Description
            0 – –  NCS向后兼容
            1 0 –  本標(biāo)準(zhǔn)
            1 1 0  Microsoft向后兼容
            1 1 1  ITU-T Rec. X.667保留

            o 版本

            UUID的生成有時(shí)間、名稱、隨機(jī)數(shù)三種策略,以第9字節(jié)(VersionAndTimeHigh)的最高4位表示。

            目前UUID定義有5個(gè)版本:

            7 6 5 4  Ver  Description
            0 0 0 1  1    基于時(shí)間的版本(本標(biāo)準(zhǔn))
            0 0 0 0  2    使用嵌入式POSIX(DCE安全版本)
            0 0 1 1  3    使用MD5哈希的基于名稱的版本(本標(biāo)準(zhǔn))
            0 1 0 0  4    基于隨機(jī)數(shù)的版本(本標(biāo)準(zhǔn))
            0 1 0 1  5    使用SHA-1的基于名稱的版本(本標(biāo)準(zhǔn))

            o 時(shí)間

            時(shí)間是一個(gè)60位的整型值(除4位版本號(hào)外的前8字節(jié)),對(duì)應(yīng)UTC(格林尼治時(shí)間1582年10月15日午夜始)的100ns時(shí)間間隔計(jì)數(shù)。

            對(duì)于ver 4和5,該值分別對(duì)應(yīng)一個(gè)隨機(jī)數(shù)和一個(gè)全局唯一的名稱。

            o 時(shí)鐘序列

            對(duì)基于時(shí)間的UUID版本,時(shí)間序列用于避免因時(shí)間向后設(shè)置或節(jié)點(diǎn)值改變可能造成的UUID重復(fù),對(duì)基于名稱或隨機(jī)數(shù)的版本同樣有用:目的都是為了防止UUID重復(fù)。

            如果前一時(shí)鐘序列已知,通過(guò)自增實(shí)現(xiàn)時(shí)鐘序列值的改變;否則,通過(guò)密碼學(xué)(偽)隨機(jī)數(shù)設(shè)置新的時(shí)鐘序列值。

            o 節(jié)點(diǎn)

            對(duì)基于時(shí)間的UUID版本,節(jié)點(diǎn)由48位的單播MAC地址構(gòu)成。對(duì)于沒(méi)有MAC地址的系統(tǒng),節(jié)點(diǎn)值為一個(gè)密碼學(xué)(偽)隨機(jī)數(shù)(為防止與MAC地址發(fā)生碰撞,需設(shè)置多播位)。


            o 基于時(shí)間的UUID生成算法

            o 確定UTC時(shí)間(60位 Time)和時(shí)間序列值(14位 ClockSequence);

            o 設(shè)置TimeLow(對(duì)應(yīng)Time的31-0位);

            o 設(shè)置TimeMid(對(duì)應(yīng)Time的47-32位);

            o 設(shè)置VersionAndTimeHigh(4位版本號(hào)及Time的59-48位);

            o 設(shè)置VariantAndClockSeqHigh(變體位及對(duì)應(yīng)ClockSequence的13-8位);

            o 設(shè)置ClockSeqLow(對(duì)應(yīng)ClockSequence的7-0位);

            o 設(shè)置Node(對(duì)應(yīng)48位MAC地址)。

            o 基于名稱的UUID生成算法

            o 針對(duì)相應(yīng)的命名空間(如DNS、URL、OID等)分配一個(gè)UUID作為所有UUID的命名空間標(biāo)識(shí);

            o 將名稱轉(zhuǎn)換為字節(jié)數(shù)列;

            o 使用MD5或SHA-1算法對(duì)與名稱關(guān)聯(lián)的命名空間標(biāo)識(shí)進(jìn)行計(jì)算,產(chǎn)生16字節(jié)哈希結(jié)果;

            o 設(shè)置TimeLow(對(duì)應(yīng)哈希值的3-0字節(jié));

            o 設(shè)置TimeMid(對(duì)應(yīng)哈希值的5-4字節(jié));

            o 設(shè)置VersionAndTimeHigh(對(duì)應(yīng)哈希值的7-6字節(jié)),以相應(yīng)版本號(hào)重寫對(duì)應(yīng)位(第9字節(jié)的高4位);

            o 設(shè)置VariantAndClockSeqHigh(對(duì)應(yīng)哈希值的第8字節(jié)),重寫變體對(duì)應(yīng)位(第7字節(jié)的高2位,本標(biāo)準(zhǔn)對(duì)應(yīng)值為10);

            o 設(shè)置ClockSeqLow(對(duì)應(yīng)哈希值的第9字節(jié));

            o 設(shè)置Node(對(duì)應(yīng)哈希值的15-10字節(jié))。

            由 于MD5碰撞問(wèn)題,MD5只用于向后兼容的UUID生成,不再被推薦使用。由于SHA-1哈希結(jié)果為160位(20字節(jié)),本算法中,需要將FIPS PUB 180-2中的SHA-1算法的哈希值字節(jié)順序反轉(zhuǎn)(字節(jié)內(nèi)順序不變),UUID使用其15-0字節(jié),19-16字節(jié)被丟棄。

            o 基于隨機(jī)數(shù)的UUID生成算法

            o 設(shè)置VariantAndClockSeqHigh的變體位值為10;

            o 設(shè)置VersionAndTimeHigh的4位版本號(hào);

            o 設(shè)置剩余位為隨機(jī)值。

            本文中討論的密碼學(xué)隨機(jī)數(shù),主要根據(jù)系統(tǒng)可以提供的信息(內(nèi)存、硬盤、句柄、程序運(yùn)行的線程、進(jìn)程、句柄、堆棧等),利用SHA-1等哈希算法得到。

            其他關(guān)于密碼學(xué)隨機(jī)數(shù)的描述,我曾在這篇文章中簡(jiǎn)單提到。


            具體算法實(shí)現(xiàn)可以參考文檔和開(kāi)源代碼。

            posted @ 2009-12-06 15:07 Fox 閱讀(21532) | 評(píng)論 (2)編輯 收藏

            2009年9月22日

            本文同步自游戲人生

            以前曾經(jīng)討論過(guò)Singleton的實(shí)現(xiàn),這次在對(duì)照ACE和Boost代碼的時(shí)候,又重新審視了一下二者對(duì)Singleton不同的實(shí)現(xiàn)。其間的差別也體現(xiàn)了不同的編程哲學(xué):ACE的實(shí)現(xiàn)更加偏重多線程中的安全和效率問(wèn)題;Boost的實(shí)現(xiàn)則偏重于使用語(yǔ)言自身的特性滿足Singleton模式的基本需求。

            o ACE的實(shí)現(xiàn)

            Douglas C. Schmidt在Double-Checked Locking: An Optimization Pattern for Efficiently Initializing and Accessing Thread-safe Objects一文中對(duì)double-check lock(一般譯為雙檢鎖)進(jìn)行了詳細(xì)的闡述。

            ACE的Singleton使用Adapter模式實(shí)現(xiàn)對(duì)其他類的適配,使之具有全局唯一的實(shí)例。由于C++標(biāo)準(zhǔn)并非明確指定全局靜態(tài)對(duì)象的初始化順序,ACE使用double-check lock保證線程安全,并使之不受全局靜態(tài)對(duì)象初始化順序的影響,同時(shí)也避免了全局靜態(tài)實(shí)現(xiàn)方式的初始化后不使用的開(kāi)銷。

            如果你能夠準(zhǔn)確的區(qū)分以下三種實(shí)現(xiàn)的弊端和隱患,對(duì)double-check lock也就有了足夠的了解。

            // -------------------------------------------
            class Singleton
            {
            public:
                static Singleton *instance (void)
                {
                    // Constructor of guard acquires
                    // lock_ automatically.
                    Guard<Mutex> guard (lock_);
                    // Only one thread in the
                    // critical section at a time.
                    if (instance_ == 0)
                        instance_ = new Singleton;
                    return instance_;
                    // Destructor of guard releases
                    // lock_ automatically.
                }
            private:
                static Mutex lock_;
                static Singleton *instance_;
            };

            // ---------------------------------------------
            static Singleton *instance (void)
            {
                if (instance_ == 0) {
                    Guard<Mutex> guard (lock_);
                    // Only come here if instance_
                    // hasn’t been initialized yet.
                    instance_ = new Singleton;
                }
                return instance_;
            }

            // ---------------------------------------------
            class Singleton
            {
            public:
                static Singleton *instance (void)
                {
                    // First check
                    if (instance_ == 0)
                    {
                        // Ensure serialization (guard
                        // constructor acquires lock_).
                        Guard<Mutex> guard (lock_);
                        // Double check.
                        if (instance_ == 0)
                            instance_ = new Singleton;
                    }
                    return instance_;
                    // guard destructor releases lock_.
                }
            private:
                static Mutex lock_;
                static Singleton *instance_;
            };

            更多詳情,見(jiàn)Schmidt老師的原文和ACE_Singleton實(shí)現(xiàn)。

            o Boost的實(shí)現(xiàn)

            Boost的Singleton也是線程安全的,而且沒(méi)有使用鎖機(jī)制。當(dāng)然,Boost的Singleton有以下限制(遵從這些限制,可以提高效率):

            o The classes below support usage of singletons, including use in program startup/shutdown code, AS LONG AS there is only one thread running before main() begins, and only one thread running after main() exits.

            o This class is also limited in that it can only provide singleton usage for classes with default constructors.

            // T must be: no-throw default constructible and no-throw destructible
            template <typename T>
            struct singleton_default
            {
            private:
                struct object_creator
                {
                    // This constructor does nothing more than ensure that instance()
                    //  is called before main() begins, thus creating the static
                    //  T object before multithreading race issues can come up.
                    object_creator() { singleton_default<T>::instance(); }
                    inline void do_nothing() const { }
                };
                static object_creator create_object;

                singleton_default();

            public:
                typedef T object_type;

                // If, at any point (in user code), singleton_default<T>::instance()
                //  is called, then the following function is instantiated.
                static object_type & instance()
                {
                    // This is the object that we return a reference to.
                    // It is guaranteed to be created before main() begins because of
                    //  the next line.
                  static object_type obj;

                  // The following line does nothing else than force the instantiation
                  //  of singleton_default<T>::create_object, whose constructor is
                  //  called before main() begins.
                  create_object.do_nothing();

                  return obj;
                }
            };
            template <typename T>
            typename singleton_default<T>::object_creator
            singleton_default<T>::create_object;

            對(duì)于多數(shù)Singleton使用,Boost提供的版本完全能夠滿足需求。為了效率,我們有必要對(duì)其使用作出一定的限制。

            而在多線程編程中,則有必要使用double-check lock降低頻繁加鎖帶來(lái)的開(kāi)銷。

            -------------------------------------------------------------------------------

            PS: 欣賞Soft的一句話:經(jīng)得起誘惑,耐得住寂寞。

            posted @ 2009-09-22 00:38 Fox 閱讀(7440) | 評(píng)論 (9)編輯 收藏

            2009年9月12日

            本文同步自游戲人生

            在使用IOCP時(shí),最重要的幾個(gè)API就是GetQueueCompeltionStatus、WSARecv、WSASend,數(shù)據(jù)的I/O及其完成狀態(tài)通過(guò)這幾個(gè)接口獲取并進(jìn)行后續(xù)處理。

            GetQueueCompeltionStatus attempts to dequeue an I/O completion packet from the specified I/O completion port. If there is no completion packet queued, the function waits for a pending I/O operation associated with the completion port to complete.

            BOOL WINAPI GetQueuedCompletionStatus(
              __in   HANDLE CompletionPort,
              __out  LPDWORD lpNumberOfBytes,
              __out  PULONG_PTR lpCompletionKey,
              __out  LPOVERLAPPED *lpOverlapped,
              __in   DWORD dwMilliseconds
            );

            If the function dequeues a completion packet for a successful I/O operation from the completion port, the return value is nonzero. The function stores information in the variables pointed to by the lpNumberOfBytes, lpCompletionKey, and lpOverlapped parameters.

            除了關(guān)心這個(gè)API的in & out(這是MSDN開(kāi)頭的幾行就可以告訴我們的)之外,我們更加關(guān)心不同的return & out意味著什么,因?yàn)橛捎诟鞣N已知或未知的原因,我們的程序并不總是有正確的return & out。

            If *lpOverlapped is NULL and the function does not dequeue a completion packet from the completion port, the return value is zero. The function does not store information in the variables pointed to by the lpNumberOfBytes and lpCompletionKey parameters. To get extended error information, call GetLastError. If the function did not dequeue a completion packet because the wait timed out, GetLastError returns WAIT_TIMEOUT.

            假設(shè)我們指定dwMilliseconds為INFINITE。

            這里常見(jiàn)的幾個(gè)錯(cuò)誤有:

            WSA_OPERATION_ABORTED (995): Overlapped operation aborted.

            由于線程退出或應(yīng)用程序請(qǐng)求,已放棄I/O 操作。

            MSDN: An overlapped operation was canceled due to the closure of the socket, or the execution of the SIO_FLUSH command in WSAIoctl. Note that this error is returned by the operating system, so the error number may change in future releases of Windows.

            成因分析:這個(gè)錯(cuò)誤一般是由于peer socket被closesocket或者WSACleanup關(guān)閉后,針對(duì)這些socket的pending overlapped I/O operation被中止。

            解決方案:針對(duì)socket,一般應(yīng)該先調(diào)用shutdown禁止I/O操作后再調(diào)用closesocket關(guān)閉。

            嚴(yán)重程度輕微易處理。

            WSAENOTSOCK (10038): Socket operation on nonsocket.

            MSDN: An operation was attempted on something that is not a socket. Either the socket handle parameter did not reference a valid socket, or for select, a member of an fd_set was not valid.

            成因分析:在一個(gè)非套接字上嘗試了一個(gè)操作。

            使用closesocket關(guān)閉socket之后,針對(duì)該invalid socket的任何操作都會(huì)獲得該錯(cuò)誤。

            解決方案:如果是多線程存在對(duì)同一socket的操作,要保證對(duì)socket的I/O操作邏輯上的順序,做好socket的graceful disconnect。

            嚴(yán)重程度輕微易處理

            WSAECONNRESET (10054): Connection reset by peer.

            遠(yuǎn)程主機(jī)強(qiáng)迫關(guān)閉了一個(gè)現(xiàn)有的連接。

            MSDN: An existing connection was forcibly closed by the remote host. This normally results if the peer application on the remote host is suddenly stopped, the host is rebooted, the host or remote network interface is disabled, or the remote host uses a hard close (see setsockopt for more information on the SO_LINGER option on the remote socket). This error may also result if a connection was broken due to keep-alive activity detecting a failure while one or more operations are in progress. Operations that were in progress fail with WSAENETRESET. Subsequent operations fail with WSAECONNRESET.

            成因分析:在使用WSAAccpet、WSARecv、WSASend等接口時(shí),如果peer application突然中止(原因如上所述),往其對(duì)應(yīng)的socket上投遞的operations將會(huì)失敗。

            解決方案:如果是對(duì)方主機(jī)或程序意外中止,那就只有各安天命了。但如果這程序是你寫的,而你只是hard close,那就由不得別人了。至少,你要知道這樣的錯(cuò)誤已經(jīng)出現(xiàn)了,就不要再費(fèi)勁的繼續(xù)投遞或等待了。

            嚴(yán)重程度輕微易處理

            WSAECONNREFUSED (10061): Connection refused.

            由于目標(biāo)機(jī)器積極拒絕,無(wú)法連接。

            MSDN: No connection could be made because the target computer actively refused it. This usually results from trying to connect to a service that is inactive on the foreign host—that is, one with no server application running.

            成因分析:在使用connect或WSAConnect時(shí),服務(wù)器沒(méi)有運(yùn)行或者服務(wù)器的監(jiān)聽(tīng)隊(duì)列已滿;在使用WSAAccept時(shí),客戶端的連接請(qǐng)求被condition function拒絕。

            解決方案:Call connect or WSAConnect again for the same socket. 等待服務(wù)器開(kāi)啟、監(jiān)聽(tīng)空閑或查看被拒絕的原因。是不是長(zhǎng)的丑或者錢沒(méi)給夠,要不就是服務(wù)器拒絕接受天價(jià)薪酬自主創(chuàng)業(yè)去了?

            嚴(yán)重程度輕微易處理。

            WSAENOBUFS (10055): No buffer space available.

            由于系統(tǒng)緩沖區(qū)空間不足或列隊(duì)已滿,不能執(zhí)行套接字上的操作。

            MSDN: An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.

            成因分析:這個(gè)錯(cuò)誤是我查看錯(cuò)誤日志后,最在意的一個(gè)錯(cuò)誤。因?yàn)榉?wù)器對(duì)于消息收發(fā)有明確限制,如果緩沖區(qū)不足應(yīng)該早就處理了,不可能待到send/recv失敗啊。而且這個(gè)錯(cuò)誤在之前的版本中幾乎沒(méi)有出現(xiàn)過(guò)。這也是這篇文章的主要內(nèi)容。像connect和accept因?yàn)榫彌_區(qū)空間不足都可以理解,而且危險(xiǎn)不高,但如果send/recv造成擁堵并惡性循環(huán)下去,麻煩就大了,至少說(shuō)明之前的驗(yàn)證邏輯有疏漏。

            WSASend失敗的原因是:The Windows Sockets provider reports a buffer deadlock. 這里提到的是buffer deadlock,顯然是由于多線程I/O投遞不當(dāng)引起的。

            解決方案:在消息收發(fā)前,對(duì)最大掛起的消息總的數(shù)量和容量進(jìn)行檢驗(yàn)和控制。

            嚴(yán)重程度嚴(yán)重。

            本文主要參考MSDN

            ************* 說(shuō)明 *************

            Fox只是對(duì)自己關(guān)心的幾個(gè)錯(cuò)誤和API參照MSDN進(jìn)行分析,不提供額外幫助。

            posted @ 2009-09-12 00:20 Fox 閱讀(8805) | 評(píng)論 (9)編輯 收藏

            2009年9月10日

            本文同步自游戲人生

            周偉明老師應(yīng)該是多核計(jì)算領(lǐng)域的老人了。

            這幾日因?yàn)橄胝艺覠o(wú)鎖(lock-free)方面的信息,就打開(kāi)了周老師的blog??吹?a target="_blank">多核系統(tǒng)中三種典型鎖競(jìng)爭(zhēng)的加速比分析這篇文章時(shí),覺(jué)得老師強(qiáng)調(diào)多核計(jì)算效率是有必要的,但拿Amdahl 定律和Gustafson定律作對(duì)比有點(diǎn)不恰當(dāng)。

            按照我的理解,這兩個(gè)定律所刻畫(huà)的內(nèi)容是完全一致的,只是對(duì)加速比的定義不一樣罷了。這里,我們都以S(n)表示n核系統(tǒng)對(duì)具體程序的加速比,K表示串行部分計(jì)算時(shí)間比例。

            Amdahl 定律的加速比:S(n) = 使用1個(gè)處理器的串行計(jì)算時(shí)間 / 使用n個(gè)處理器的并行計(jì)算時(shí)間

            S(n) = 1/(K+(1-K)/n) = n/(1+(n-1)K)

            Gustafson定律的加速比:S(n) = 使用n個(gè)處理器的并行計(jì)算量 / 使用1個(gè)處理器的串行計(jì)算量

            S(n) = K+(1-K)n

            通俗的講,Amdahl 定律將工作量看作1,有n核也只能分擔(dān)1-K的工作量;而Gustafson定律則將單核工作量看作1,有n核,就可以增加n(1-K)的工作量。

            這兩個(gè)計(jì)算公式都沒(méi)有將鎖開(kāi)銷考慮在內(nèi),是理想化的。周老師提到設(shè)計(jì)不當(dāng)造成并行變串行的問(wèn)題與這兩個(gè)公式計(jì)算無(wú)關(guān)。因?yàn)槿魏味嗪擞?jì)算都存在對(duì)串行和并行的設(shè)計(jì)考量,這正是程序員在使用多核并行時(shí)最關(guān)心的事情。

            總之,二者的區(qū)別只在于態(tài)度的不同:一個(gè)消極悲觀,一個(gè)積極樂(lè)觀,充其量是一個(gè)冷笑話,而于多核計(jì)算沒(méi)有任何關(guān)聯(lián)。

            我說(shuō)這些也與多核計(jì)算沒(méi)有關(guān)聯(lián),絲毫沒(méi)有質(zhì)疑多核效率的意思。相反,我期待能夠通過(guò)技術(shù)層面提高多核的有效負(fù)載。

            最后一句題外話,周老師使用Word的水平一般:所有來(lái)自Word的截圖都是在頁(yè)面視圖直接截,換行符和光標(biāo)隨處可見(jiàn)。

            posted @ 2009-09-10 12:04 Fox 閱讀(6306) | 評(píng)論 (0)編輯 收藏

            2009年9月1日

            本文同步自游戲人生

            o *__ 序 __* o

            在閱讀ACE代碼和C++NPv1, v2, APG的時(shí)候,我意識(shí)到一個(gè)問(wèn)題:雖然稍有C++和網(wǎng)絡(luò)基礎(chǔ)的同學(xué)都可以讀懂ACE,但如果你對(duì)OS(五大管理模塊都包含在內(nèi))、TCP/IP、C++、Design Patterns了解越多,你就越能體會(huì)ACE為什么需要這么龐雜,雖然它不夠完美(但至少我還沒(méi)有資格來(lái)批評(píng)這一點(diǎn),我現(xiàn)在最常想做的一個(gè)動(dòng)作就是五體投地)。

            而且我隱約感覺(jué)到,我現(xiàn)在所寫的很多東西在以后(對(duì)于有些人或許就是現(xiàn)在)看來(lái)會(huì)相當(dāng)不深刻、相當(dāng)不嚴(yán)謹(jǐn),但對(duì)于一段學(xué)習(xí)歷程,這個(gè)過(guò)程是必然的、必需的。

            在C++NPv1中,Douglas C. Schmidt把原始socket及其API的缺陷有些妖魔化了,比如一段加上注釋、空行在內(nèi)的35行的代碼,被指出有10處錯(cuò)誤之多。這就像很多其他語(yǔ)言的倡導(dǎo)者或反傳統(tǒng)C/C++指針者在批評(píng)指針時(shí)的說(shuō)法一樣。長(zhǎng)期使用原始socket和指針的同學(xué)對(duì)此感覺(jué)很不舒服,何況socket API提供了大量錯(cuò)誤檢測(cè)的接口,至多是不夠友好罷了。你好就好了,沒(méi)必要抓住別人一頓痛批吧,『本是同根生,相煎何太急』。

            雖然Solaris、Linux的很多版本及Windows對(duì)起源于Berkeley的socket API進(jìn)行了重寫,但不可否認(rèn),由于歷史原因和POSIX標(biāo)準(zhǔn)的存在,對(duì)于使用者而言,我們可以無(wú)視這些API的實(shí)現(xiàn)差異。只是一旦我們從socket通信擴(kuò)展到其他IPC通信的話,就需要正視各種I/O細(xì)節(jié)的差異了。

            由于UNIX中,對(duì)于socket, file, pipe, device的大多數(shù)操作,描述符都是通用的(這一點(diǎn),OS上面講的更清楚些)。而Windows中,句柄大多不能互換(socket對(duì)于MS來(lái)說(shuō)是舶來(lái)品)。系統(tǒng)和標(biāo)準(zhǔn)的不一致導(dǎo)致地址、協(xié)議和API的混雜甚至混亂。

            UNIX下的描述符和Windows的句柄可以看作是同一個(gè)概念,只是應(yīng)用環(huán)境不一樣,所描述的內(nèi)容也時(shí)常不一樣,再簡(jiǎn)單了說(shuō),它們都是一個(gè)整型的ID。

            ACE的源碼中使用了大量預(yù)處理指令,尤其在跨平臺(tái)/編譯環(huán)境的部分更加明顯。鑒于C/C++標(biāo)準(zhǔn)的博大胸懷,有些指令需要閱讀相關(guān)編譯器提供的幫助文檔:

            o #pragma: GCC, MSVC

            o #define (#, #@, ##) : GCC, MSVC

            其中有若干代碼文件以.inl為后綴,里面是對(duì)部分函數(shù)的內(nèi)聯(lián)實(shí)現(xiàn),以使代碼結(jié)構(gòu)看上去更加簡(jiǎn)潔。如果確定使用內(nèi)聯(lián)函數(shù)的話,*.inl將被包含于*.h的最后,如果不使用,則像*.h一樣,包含于*.cpp的頭部。

            ACE采用doxygen輸出文檔,在閱讀代碼注釋時(shí)能夠感受到差異,但基本不會(huì)影響閱讀。

            o * __ 關(guān)于第3章(C++NPv1)__ * o

            ACE抽象的地址類ACE_Addr擁有ACE_DEV_Addr, ACE_FILE_Addr, ACE_INET_Addr, ACE_SPIPE_Addr, ACE_UNIX_Addr五個(gè)子類。對(duì)于狹義上的網(wǎng)絡(luò)通信(TCP/IP)而言,ACE_INET_Addr對(duì)應(yīng)于我們熟悉的sockaddr_in。

            ACE_IPC_SAP是IPC(interprocess communication)I/O操作類的root類。

            從編碼的角度看,這個(gè)類漂亮的地方在于示例了抽象類的另一種實(shí)現(xiàn)方式。

            一提到抽象類,大多數(shù)人的第一反應(yīng)是pure virtual function。當(dāng)一個(gè)基類確定需要使用virtual function時(shí),這是一個(gè)不錯(cuò)的選擇。但我們都知道虛擬函數(shù)有開(kāi)銷。而且對(duì)于一個(gè)結(jié)構(gòu)簡(jiǎn)單的抽象基類和其繼承子類(尤其是大量使用時(shí)),一個(gè)虛函數(shù)表帶來(lái)的開(kāi)銷會(huì)讓整個(gè)設(shè)計(jì)顯得十分蹩腳。

            我們都知道如何強(qiáng)制讓一個(gè)類無(wú)法使用default constructor(protected)。如果對(duì)基類使用該方法,僅使子類具有public的default constructor,這就達(dá)到了定義抽象基類的效果。

            virtual destructor的意義在于防止delete父類指針(指向子類對(duì)象)時(shí)未調(diào)用子類destructor。在此例中,為避免這種情況,同樣將destructor聲明為protected即可。

            從設(shè)計(jì)實(shí)現(xiàn)的角度看,相較于socket API,ACE_IPC_SAP的子類ACE_SOCK提供了編譯時(shí)對(duì)句柄合法性的檢測(cè)。

            從邏輯功能層面劃分,socket有三種角色:

            o active connection role (connector):主動(dòng)連接

            o passive connection role (acceptor):被動(dòng)連接

            o communication role (stream):數(shù)據(jù)通信

            但socket API畢竟不是OOD出來(lái)的,對(duì)于一個(gè)socket描述符,也完全沒(méi)有必要去限制其擔(dān)負(fù)的功能,更不可能搞成三種不同的socket。而OOD的ACE則可以輕易實(shí)現(xiàn)對(duì)socket對(duì)象及其操作的封裝。

            工廠類ACE_SOCK_Connector是一個(gè)主動(dòng)創(chuàng)建通信端的工廠類。socket API中的connect接口只是為一個(gè)socket建立與其它peer的網(wǎng)絡(luò)連接,而不產(chǎn)生新的socket實(shí)例,也不依賴于任何其它socket。同樣,ACE_SOCK_Connector只是為一個(gè)ACE_SOCK_Stream對(duì)象(對(duì)用于數(shù)據(jù)通信的socket的封裝)連接到ACE_Addr(對(duì)struct sockaddr的封裝)提供接口,也不含對(duì)ACE_SOCK_Stream對(duì)象的其它操作。

            工廠類ACE_SOCK_Acceptor是一個(gè)被動(dòng)創(chuàng)建通信端的工廠類。當(dāng)監(jiān)聽(tīng)到新的網(wǎng)絡(luò)連接后,為該連接初始化一個(gè)ACE_SOCK_Stream對(duì)象。和connector不同的是,acceptor依賴于一個(gè)已經(jīng)存在的充當(dāng)監(jiān)聽(tīng)功能的socket句柄(ACE_SOCK),因此,ACE_SOCK_Acceptor是ACE_SOCK的一個(gè)子類。

            ACE_SOCK_Stream是只負(fù)有通信傳輸功能的socket,對(duì)應(yīng)connection-oriented的TCP通信格式stream,和UDP的CE_SOCK_CODgram相呼應(yīng)。ACE_SOCK_Stream只是socket的通信載體,在兩個(gè)工廠ACE_SOCK_Connector和ACE_SOCK_Acceptor中初始化。這樣一個(gè)類除支持最基本的數(shù)據(jù)發(fā)送(send)和接收(recv)和阻塞(blocking)、非阻塞(nonblocking)及定時(shí)(timed)的I/O模式外,還支持分散讀取(scatter-read)和集中寫入(gather-write)。

            對(duì)于一個(gè)簡(jiǎn)單的『網(wǎng)絡(luò)課程作業(yè):寫一個(gè)有連接的IM小程序』,上面這些內(nèi)容已經(jīng)足夠了。當(dāng)然即使使用對(duì)應(yīng)的幾個(gè)socket API也已經(jīng)足夠了。但我們顯然更加關(guān)心如此龐大的一個(gè)庫(kù),是如何解決復(fù)雜的網(wǎng)絡(luò)應(yīng)用的,我尤其關(guān)心的是多線程并發(fā)如何更好的處理。

            所以,我準(zhǔn)備跑到第8、9章了。

            posted @ 2009-09-01 14:22 Fox 閱讀(3894) | 評(píng)論 (3)編輯 收藏

            2009年8月28日

            本文同步自游戲人生

            我發(fā)現(xiàn)我最近成了Cygwin下的小白鼠,寫完Cygwin下安裝ACE,寫ACE在cygwin下的使用?,F(xiàn)在又寫doxygen。

            之前提到在Cygwin下讀代碼的不習(xí)慣,后來(lái)回到VS下看。沒(méi)過(guò)幾天,覺(jué)得VS下還是不夠直觀,于是就直接看ACE的doxygen了……

            doxygen好是好,用起來(lái)還是要慢慢習(xí)慣才行,需要在寫注釋和代碼的時(shí)候注意一些,掌握的細(xì)節(jié)和技巧越多,出來(lái)的文檔越豐富(當(dāng)然,這和代碼質(zhì)量是兩碼事)。

            我自然是把doxygen安裝在Cygwin下了,由于doxygen沒(méi)有提供info,Info doxygen時(shí)就自動(dòng)打開(kāi)了doxygen的man,和man doxygen、doxygen --help一個(gè)效果。

            如果希望閱讀更詳盡的使用方法,只有自己down一個(gè)manual了。

            在Cygwin下,doxygen采用GNU的libiconv進(jìn)行文字編碼的轉(zhuǎn)換,以UTF-8作為默認(rèn)編碼。

            使用doxygen生成config-file模板后,可以在config-file中進(jìn)行一些項(xiàng)目設(shè)置(有注釋的,看的懂)。

            為了支持中文,我DOXYFILE_ENCODING用的是EUC-CN,但輸出文檔的語(yǔ)言O(shè)UTPUT_LANGUAGE卻選了English。兩點(diǎn)原因:

            o EUC-CN(各種漢字編碼知識(shí)就不在此普及了,你可以認(rèn)為簡(jiǎn)體字編碼都是EUC-CN)和UTF-8不同,但OUTPUT_LANGUAGE的各種語(yǔ)言都是使用的UTF-8,所以兩種編碼不可能同時(shí)顯示,當(dāng)然,你可以把EUC-CN全轉(zhuǎn)成UTF-8。編碼不是高級(jí)的技術(shù),但對(duì)于非英語(yǔ)用戶絕對(duì)是一個(gè)噩夢(mèng),后來(lái)發(fā)現(xiàn)是我自己學(xué)藝不精,DOXYFILE_ENCODING只是配置文件的編碼格式而已,而識(shí)別中文文檔只需要修改INPUT_ENCODING成EUC-CN即可,OUTPUT_LANGUAGE自然設(shè)置成Chinese也不會(huì)有問(wèn)題,因?yàn)閐oxygen采用UTF-8輸出,使用中文輸出不會(huì)有亂碼問(wèn)題。

            o 雖然我的英文很蹩腳,雖然我的文檔中多有中文注釋。但像doxygen中文輸出的文檔中把class、public都給你翻譯成中文,你也受不了,這也英文水平無(wú)關(guān)。

            config-file中的其他內(nèi)容我現(xiàn)在也用不到,就沒(méi)有仔細(xì)看。

            因?yàn)?a href="http://www.shnenglu.com/kevinlynx/" target="_blank">Kevin會(huì)在公司里講一下doxygen,doxygen的manual也講的很詳細(xì),我就省點(diǎn)時(shí)間,不翻譯文檔了。

            簡(jiǎn)單的一個(gè)Doxygen的測(cè)試在這里。

            posted @ 2009-08-28 17:14 Fox 閱讀(2915) | 評(píng)論 (5)編輯 收藏

            2009年8月24日

            本文同步自游戲人生

            我屈服了,還是VS用的方便。

            之前在Cygwin下已經(jīng)可以使用的ACE,因?yàn)殚喿x代碼太不方便(對(duì)于一個(gè)WinEr來(lái)說(shuō)),上午在VS下面花了幾分鐘就把ACE配好了,而且使用$(ACE_ROOT)\examples\C++NPv1的代碼跟蹤調(diào)試,太習(xí)慣了。

            按照$(ACE_ROOT)\ACE-INSTALL.html的安裝說(shuō)明:

            o 選擇并打開(kāi)$(ACE_ROOT)\ace\ace_vc9.sln

            o 添加config.h并加入以下內(nèi)容:

                #define ACE_HAS_STANDARD_CPP_LIBRARY 1
                #include "ace/config-win32.h"

            o F7

            -----------------------------------------------

            OK,現(xiàn)在$(ACE_ROOT)\lib下面已經(jīng)生成了ACEd.dll、ACEd.lib,再設(shè)置一下系統(tǒng)環(huán)境變量(運(yùn)行程序必需)和VC++目錄(調(diào)試程序必需)??梢允褂昧耍?

            o 選擇并打開(kāi)$(ACE_ROOT)\examples\C++NPv1

            o F7

            o for (; ; ) { F12, F9, F5, F10, F11 }

            -----------------------------------------------

            半個(gè)小時(shí)就搞定了當(dāng)時(shí)一個(gè)星期的折騰……

            結(jié)論:對(duì)于一個(gè)不忠實(shí)的Win Coder,在MinGW, Cygwin, UNIX…下面裝B是要付出代價(jià)的。

            當(dāng)然,家里的機(jī)器就讓它還一直跑Cygwin吧。

            posted @ 2009-08-24 11:59 Fox 閱讀(2526) | 評(píng)論 (6)編輯 收藏

            2009年8月19日

            本文同步自游戲人生

            /*--------- Hello.cc ---------*/

            /** Hello.cc:
            * @File:   Hello.cc
            * @Author: Fox <yulefox at gmail dot com>
            * @Date:   Aug. 19th, 2009
            * @Brief:  Test ACE log module application
            */

            #define ACE_NTRACE 0            /// trace the calling position

            #include "ace/Log_Msg.h"        /// include log module

            int ACE_TMAIN(int, ACE_TCHAR *[])
            {
                 ACE_TRACE(ACE_TEXT("main"));

                 ACE_DEBUG((LM_INFO, ACE_TEXT("%IStart\n")));
                 ACE_DEBUG((LM_INFO, ACE_TEXT("%IEnd\n")));

                 return 0;
            }

            /*--------- makefile ---------*/

            BIN     = hello                       # src & exe file name
            SRC     = $(addsuffix .cc, $(BIN))    # src file suffix
            LIBS    = -lACE                       # libACE.dll under cygwin

            include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU
            include $(ACE_ROOT)/include/makeinclude/macros.GNU
            include $(ACE_ROOT)/include/makeinclude/rules.common.GNU
            include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU
            include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU
            include $(ACE_ROOT)/include/makeinclude/rules.local.GNU

            /*--------- Compilation ---------*/

            GNUmakefile: /home/fox/ace/GNUmakefile MAKEFLAGS=k

            g++ -Wpointer-arith -mthreads -mtune=pentiumpro -O3 -g -pipe    -pipe   -I/usr/\
            share/ace -DACE_HAS_EXCEPTIONS -DACE_NO_INLINE  -c -o .obj/hello.o hello.cc
            g++ -Wpointer-arith -mthreads -mtune=pentiumpro -O3 -g -pipe    -pipe   -I/usr/\
            share/ace -DACE_HAS_EXCEPTIONS -DACE_NO_INLINE  -Wl,--enable-auto-import -Wl,-E\
            -L/usr/share/ace/lib -o hello .obj/hello.o  -lACE

            Compilation finished at Wed Aug 19 00:35:42

            /*--------- Result ---------*/

            $ ./hello.exe
            (14417928) calling main in file `hello.cc' on line 13
                Start
                End
            (14417928) leaving main

            -------------------------------------------------------

            更多內(nèi)容請(qǐng)參考C++NP(C++ Network Programming) vol.1 & vol.2和APG(The ACE Progrmmer's Guide)。

            忙活了一晚上,終于知道怎么包含頭文件了,在gcc的編譯選項(xiàng)中用 -I或/I$(ACE_ROOT):

            本例中是:-I/usr/share/ace

            結(jié)果后面庫(kù)又鏈接不上,聯(lián)想以前使用OpenGL庫(kù)的LIBS,終于靠一個(gè)-lACE搞定。

            因?yàn)椴辉敢庥肕PC,總感覺(jué)再多花些時(shí)間去弄又只是離題更遠(yuǎn)了,有興趣的同學(xué)自然是可以通過(guò)ACE的官網(wǎng)找到所有問(wèn)題的答案。

            這樣一來(lái),ACE在cygwin下從安裝到使用也就告一段落了,后面的問(wèn)題就比較easy了,無(wú)非是你用ACE做什么。而我也不會(huì)再就ACE && cygwin寫什么心得了,總算見(jiàn)證了這兩天的搗騰。

            posted @ 2009-08-19 10:05 Fox 閱讀(2604) | 評(píng)論 (4)編輯 收藏

            久久精品一区二区| 亚洲欧洲精品成人久久奇米网| 久久精品国产72国产精福利| 久久AV高清无码| 久久久亚洲欧洲日产国码aⅴ| 亚洲伊人久久成综合人影院 | 久久久久99这里有精品10 | 亚洲狠狠婷婷综合久久蜜芽 | 日韩精品无码久久久久久| 一级A毛片免费观看久久精品| 久久精品国产精品亚洲艾草网美妙| 精品久久久久久国产| 蜜桃麻豆www久久| 99热热久久这里只有精品68| 国产精品狼人久久久久影院| 久久97久久97精品免视看| 久久夜色精品国产亚洲av| 午夜精品久久久内射近拍高清 | 精产国品久久一二三产区区别| 亚洲国产视频久久| 久久永久免费人妻精品下载| 欧美一区二区三区久久综| 91精品国产高清91久久久久久| 国产亚洲色婷婷久久99精品| 国产精品久久久久久影院| 久久亚洲精品视频| 久久午夜福利电影| 99精品国产综合久久久久五月天| 久久久久久精品无码人妻| 精品久久久久久成人AV| 91亚洲国产成人久久精品网址| 久久国产精品免费一区| 国产精品久久新婚兰兰| 精品久久久久中文字幕日本| 亚洲一区中文字幕久久| 国产精品中文久久久久久久| 亚洲精品无码久久久影院相关影片| 精品国产乱码久久久久久1区2区| 久久久久久综合一区中文字幕 | 久久亚洲AV成人无码| 大伊人青草狠狠久久|