• <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>

            2013年6月1日


            本文主要討論如何將一個(gè)win32項(xiàng)目,移植到android上面,網(wǎng)上很多文章說(shuō)的不一樣,因?yàn)閏ocos2d-x的android項(xiàng)目配置方法好像修改過(guò)幾次(好像?我沒(méi)用過(guò)老版的),本文提供一種簡(jiǎn)單的方法。

            第零步:配置android工程生成器
            #1用ue之類(lèi)的編輯器打開(kāi)cocos2d-x目錄下的create-android-project.bat

            #2編輯這三個(gè)變量

            意思太明白了,就不解釋了


            第一步:建立android工程

            #1運(yùn)行cocos2d-x目錄下的create-android-project.bat

            #2然后首先輸入包名和項(xiàng)目名。
            注意有坑!這會(huì)刪除和覆蓋你在cocos2d-x安裝目錄下同名文件夾,如果你建立了一個(gè)同名項(xiàng)目(有的話一般是win32的)的話。
            本地圖片,請(qǐng)重新上傳
            #3然后輸入支持系統(tǒng)版本,android是向下兼容的。我這里寫(xiě)5,也就是android2.1-update1
            本地圖片,請(qǐng)重新上傳
            然后項(xiàng)目就建立好了,你會(huì)發(fā)現(xiàn)在cocos2d-x安裝目錄下,多了個(gè)Test文件夾

            第二步:導(dǎo)入代碼和資源

            #1打開(kāi)Test

            本地圖片,請(qǐng)重新上傳
            #2我們看到有三個(gè)文件夾,其中android就是android項(xiàng)目文件夾
            把你win32項(xiàng)目里的Classes拷貝到當(dāng)前Classes下(注意刪除Classes里面的多余的cpp和h,就是項(xiàng)目自動(dòng)生成的那些)
            把你win32項(xiàng)目里的Resources拷貝到當(dāng)前Resources下(注意刪除Classes里面的多余資源,就是項(xiàng)目自動(dòng)生成的那些)

            第三步:編輯mk

            #1注意有坑!android項(xiàng)目里有一大堆mk,而且不同的教程說(shuō)的mk位置還不一樣!你編輯錯(cuò)誤了,是無(wú)效的(跟你實(shí)際使用的mk也有關(guān)系)。在這個(gè)例子中,我們使用的是Classes下的mk

            本地圖片,請(qǐng)重新上傳
            #2要修改的地方如下
            LOCAL_SRC_FILES:在這里加入你Classes下的cpp文件
            LOCAL_C_INCLUDES:在這里添加你使用的庫(kù)的h文件,如果有的話
            LOCAL_LDLIBS:在這里添加你使用的庫(kù)的lib文件,如果有的話

            這里我使用的是,之前的“是男人就堅(jiān)持20秒”那個(gè)例子的代碼

            注意,第三方庫(kù)和額外的庫(kù)都是要自己添加的。默認(rèn)生成的mk里沒(méi)那么全。

            第四步:運(yùn)行build_native.sh腳本,編輯so庫(kù)

            #1運(yùn)行你的cygwin安裝目錄下的Cygwin.bat

            #2進(jìn)入當(dāng)前Test\android路徑下
            本地圖片,請(qǐng)重新上傳
            注意cygwin下的命令寫(xiě)法,和win下不同
            #3運(yùn)行build_native.sh腳本
            頭一次編譯會(huì)長(zhǎng)些,當(dāng)然圖省事你也可以把自己及其他的android項(xiàng)目里面的so復(fù)制進(jìn)來(lái)(應(yīng)該可以把,哈哈哈)
            編譯完然后你會(huì)看到,在android文件夾下面生成了一大堆東西。

            第五步:導(dǎo)入到eclipse

            #1注意有坑!使用新建android項(xiàng)目下的Create project from existing source,如果你使用的是“導(dǎo)入”有可能無(wú)法識(shí)別。
            #2導(dǎo)入成功,然后就是編譯執(zhí)行了。cocos2d-x作者推薦用sh編譯so,再用eclipse編譯成apk。
            本地圖片,請(qǐng)重新上傳

            其他注意事項(xiàng):


            #1.win32項(xiàng)目對(duì)資源文件大小寫(xiě)不敏感,android敏感,所以如果出錯(cuò)了,把給你提供資源的人給打一頓
            #2.可以直接把win32項(xiàng)目里的工程文件,以及win32文件夾復(fù)制進(jìn)來(lái),項(xiàng)目就可以和VS共用了,當(dāng)然cocos2d-x也是這么干的
            #3.vs用的是gb碼,android用的是utf-8,解決方法在vs下用iconv,另外最好全都轉(zhuǎn)成utf-8,網(wǎng)上有很多編碼批量轉(zhuǎn)換工具
            #4.android的橫豎屏問(wèn)題錯(cuò)亂,在android下把
            pDirector->setDeviceOrientation(kCCDeviceOrientationLandscapeLeft);
            這句用條件編譯宏給關(guān)掉

             

             

             

            另外,關(guān)于cocos2d-x在android上添加第三方庫(kù)的問(wèn)題,6群網(wǎng)友塞風(fēng)朔雪寫(xiě)了一個(gè)文檔,很有參考價(jià)值。我已把它上傳到附件中。


            posted @ 2013-06-01 10:04 鄭興鋒 閱讀(1161) | 評(píng)論 (0)編輯 收藏

            環(huán)境winxp + android sdk + ndk r8b+ cygwin 1.7.16-1 + cocos2d-1.0.1-x-0.12.0

            1.下載android sdk、ndk、cygwin

            http://dl.google.com/android/android-sdk_r20.0.1-windows.zip

            http://dl.google.com/android/ndk/android-ndk-r8b-windows.zip

            http://cygwin.com/setup.exe

            2.android sdk的安裝就不多說(shuō)了,網(wǎng)上多的是。

            將ndk解壓到不含空格的目錄下,下文用<ndk_dir>來(lái)表示解壓后的ndk根目錄。

            下載好cygwin后,運(yùn)行setup.exe。需要安裝的組件有:

            autoconf automake binutils gcc-core gcc-g++ gcc4-core gcc4-g++ gdb pcre pcre-devel gawk make

            可以在上方search處進(jìn)行查找安裝,下文用<cyg_dir>表示cygwin的安裝目錄。

            3.cygwin安裝好后,在windows下編輯<cyg_dir>\home\Administrator\.bash_profile文件

            在文件最后添加如下內(nèi)容

             

            1. NDK=/cygdrive/d/<這里是ndk路徑>/android-ndk-r8b  
            2. export NDK  
            NDK=/cygdrive/d/<這里是ndk路徑>/android-ndk-r8bexport NDK
            編輯cocos2dx目錄下的create-android-project.bat文件,分別修改如下幾個(gè)變量的值

             

             

            1. set _CYGBIN=C:\cygwin\bin  
            2. set _ANDROIDTOOLS=C:\android-sdk-windows\tools  
            3. set _NDKROOT=D:\Tools\Developer\Android\android-ndk-r8b  
            set _CYGBIN=C:\cygwin\binset _ANDROIDTOOLS=C:\android-sdk-windows\toolsset _NDKROOT=D:\Tools\Developer\Android\android-ndk-r8b
            上面是我的系統(tǒng)中使用的路徑,同學(xué)們需要根據(jù)自己的實(shí)際情況進(jìn)行修改。

             

            這樣,環(huán)境基本上就搭建好了,下面需要建一個(gè)hello world工程來(lái)驗(yàn)證一下環(huán)境是否可用。

            1.運(yùn)行cocos2dx目錄下的create-android-project.bat文件,根據(jù)提示輸入包名(例如:cn.wey.android)、項(xiàng)目名稱(chēng)(例如:hello2dx)、所使用的android sdk版本。

            2.運(yùn)行cygwin,在命令窗口中進(jìn)入剛剛新建的hello2dx目錄下的android目錄,運(yùn)行命令

             

            1. ./build_native.sh  
            ./build_native.sh
            對(duì)工程進(jìn)行編譯,直到最后正常結(jié)束。

             

            3.打開(kāi)eclipse,導(dǎo)入hello2dx項(xiàng)目,編譯并運(yùn)行。即可看到經(jīng)典的cocos2dx的hello world界面

            posted @ 2013-06-01 10:02 鄭興鋒 閱讀(1884) | 評(píng)論 (0)編輯 收藏

            2011年11月21日

              http://blog.csdn.net/xiaominghimi?viewmode=contents 
              http://www.cnblogs.com/andyque/tag/iphone

            posted @ 2011-11-21 10:39 鄭興鋒 閱讀(318) | 評(píng)論 (0)編輯 收藏

            2011年11月20日

              最近在用VC++開(kāi)發(fā)一個(gè)小工具,平時(shí)用慣了.NET,用起VC++最郁悶的就是字符串處理。當(dāng)然最最讓人難于琢磨的就是字符集,編碼之間的轉(zhuǎn)換。通過(guò)這幾天的研究,終于明白了Unicode和UTF-8之間編碼的區(qū)別。Unicode是一個(gè)字符集,而UTF-8是Unicode的其中一種,Unicode是定長(zhǎng)的都為雙字節(jié),而UTF-8是可變的,對(duì)于漢字來(lái)說(shuō)Unicode占有的字節(jié)比UTF-8占用的字節(jié)少1個(gè)字節(jié)。Unicode為雙字節(jié),而UTF-8中漢字占三個(gè)字節(jié)。
                                    網(wǎng)魂小兵 http://xdotnet.cnblogs.com
                UTF-8編碼字符理論上可以最多到6個(gè)字節(jié)長(zhǎng),然而16位BMP(Basic Multilingual Plane)字符最多只用到3字節(jié)長(zhǎng)。下面看一下UTF-8編碼表:

                    U-00000000 - U-0000007F: 0xxxxxxx
                    U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
                    U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
                    U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
                    U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
                    U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

                xxx 的位置由字符編碼數(shù)的二進(jìn)制表示的位填入, 越靠右的 x 具有越少的特殊意義,只用最短的那個(gè)足夠表達(dá)一個(gè)字符編碼數(shù)的多字節(jié)串。 注意在多字節(jié)串中, 第一個(gè)字節(jié)的開(kāi)頭"1"的數(shù)目就是整個(gè)串中字節(jié)的數(shù)目。而第一行中以0開(kāi)頭,是為了兼容ASCII編碼,為一個(gè)字節(jié),第二行就為雙字節(jié)字符串,第三行為3字節(jié),如漢字就屬于這種,以此類(lèi)推。(個(gè)人認(rèn)為:其實(shí)我們可以簡(jiǎn)單的把前面的1的個(gè)數(shù)看成字節(jié)數(shù))
                                     網(wǎng)魂小兵 http://xdotnet.cnblogs.com
                為了要將Unicode轉(zhuǎn)換為UTF-8,當(dāng)然要知道他們的區(qū)別到底在什么地方。下面來(lái)看一下,在Unicode中的編碼是怎樣轉(zhuǎn)換成UTF-8的,在UTF-8中,如果一個(gè)字符的字節(jié)小于0x80(128)則為ASCII字符,占一個(gè)字節(jié),可以不用轉(zhuǎn)換,因?yàn)閁TF-8兼容ASCII編碼。假如在Unicode中漢字“你”的編碼為“u4F60”,把它轉(zhuǎn)換為二進(jìn)制為100111101100000,然后按照UTF-8的方法進(jìn)行轉(zhuǎn)換。可以將Unicode二進(jìn)制從地位往高位取出二進(jìn)制數(shù)字,每次取6位,如上述的二進(jìn)制就可以分別取出為如下所示的格式,前面按格式填補(bǔ),不足8位用0填補(bǔ)。

                  
                       unicode:  100111101100000                  4F60

                       utf-8:    11100100,10111101,10100000       E4BDA0


                從上面就可以很直觀的看出Unicode到UTF-8之間的轉(zhuǎn)換,當(dāng)然知道了UTF-8的格式后,就可以進(jìn)行逆運(yùn)算,就是按照格式把它在二進(jìn)制中的相應(yīng)位置上取出,然后在轉(zhuǎn)換就是所得到的Unicode字符了(這個(gè)運(yùn)算可以通過(guò)“位移”來(lái)完成)。
                                  網(wǎng)魂小兵 http://xdotnet.cnblogs.com
                如上述的“你”的轉(zhuǎn)換,由于其值大于0x800小于0x10000,因此可以判斷為三字節(jié)存儲(chǔ),則最高位需要向右移“12”位再根據(jù)三字節(jié)格式的最高位為11100000(0xE0)求或(|)就可以得到最高位的值了。同理第二位則是右移“6”位,則還剩下最高位和第二位的二進(jìn)制值,可以通過(guò)與111111(0x3F)求按位于(&)操作,再和11000000(0x80)求或(|)。第三位就不用移位了,只要直接取最后六位(與111111(ox3F)取&),在與11000000(0x80)求或(|)。OK了,轉(zhuǎn)換成功!在VC++中的代碼如下所示(Unicode到UTF-8的轉(zhuǎn)換)。

                    1 const wchar_t pUnicode = L"你";
                    2 char utf8[3+1];
                    3 memset(utf8,0,4);
                    4 utf8[0] = 0xE0|(pUnicode>>12);
                    5 utf8[1] = 0x80|((pUnicode>>6)&0x3F);
                    6 utf8[2] = 0x80|(pUnicode&0x3F);
                    7 utf8[3] = "\0";
                    8 //char[4]就是UTF-8的字符“你”了。

                當(dāng)然在UTF-8到Unicode的轉(zhuǎn)換也是通過(guò)移位等來(lái)完成的,就是把UTF-8那些格式相應(yīng)的位置的二進(jìn)制數(shù)給揪出來(lái)。在上述例子中“你”為三個(gè)字節(jié),因此要每個(gè)字節(jié)進(jìn)行處理,有高位到低位進(jìn)行處理。在UTF-8中“你”為11100100,10111101,10100000。從高位起即第一個(gè)字節(jié)11100100就是把其中的"0100"給取出來(lái),這個(gè)很簡(jiǎn)單只要和11111(0x1F)取與(&),由三字節(jié)可以得知最到位肯定位于12位之前,因?yàn)槊看稳×弧K赃€要將得到的結(jié)果左移12位,最高位也就這樣完成了0100,000000,000000。而第二位則是要把“111101”給取出來(lái),則只需將第二字節(jié)10111101和111111(0x3F)取與(&)。在將所得到的結(jié)果左移6位與最高字節(jié)所得的結(jié)果取或(|),第二位就這樣完成了,得到的結(jié)果為0100,111101,000000。以此類(lèi)推最后一位直接與111111(0x3F)取與(&),再與前面所得的結(jié)果取或(|)即可得到結(jié)果0100,111101,100000。OK,轉(zhuǎn)換成功!在VC++中的代碼如下所示(UTF-8到Unicode的轉(zhuǎn)換)。

                1 //UTF-8格式的字符串
                2 const char* utf8 = "你";
                3 wchar_t unicode;
                4 unicode = (utf8[0] & 0x1F) << 12;
                5 unicode |= (utf8[1] & 0x3F) << 6;
                6 unicode |= (utf8[2] & 0x3F);
                7 //unicode is ok!
                                        網(wǎng)魂小兵 http://xdotnet.cnblogs.com
                當(dāng)然在編程過(guò)程中不可能只轉(zhuǎn)換一個(gè)字符,這里需要注意的是字符的長(zhǎng)度一定要算清楚,不然會(huì)帶來(lái)...以上就是我這幾天研究的結(jié)果,至于Unicode的轉(zhuǎn)換為GB2312在MFC中Windows有自帶的API(WideCharToMultiByte)可以轉(zhuǎn)換。這樣也就能夠?qū)TF-8格式轉(zhuǎn)換為GB2312了,這里就不再贅述,如果大家有更好的方法希望指教。

            posted @ 2011-11-20 13:52 鄭興鋒 閱讀(360) | 評(píng)論 (0)編輯 收藏

            2011年11月16日

            1.closesocket(一般不會(huì)立即關(guān)閉而經(jīng)歷TIME_WAIT的過(guò)程)后想繼續(xù)重用該socket:
            BOOL bReuseaddr=TRUE;
            setsockopt(s,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(BOOL));
            2. 如果要已經(jīng)處于連接狀態(tài)的soket在調(diào)用closesocket后強(qiáng)制關(guān)閉,不經(jīng)歷
            TIME_WAIT的過(guò)程:
            BOOL bDontLinger = FALSE;
            setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL));
            3.在send(),recv()過(guò)程中有時(shí)由于網(wǎng)絡(luò)狀況等原因,發(fā)收不能預(yù)期進(jìn)行,而設(shè)置收發(fā)時(shí)限:
            int nNetTimeout=1000;//1秒
            //發(fā)送時(shí)限
            setsockopt(socket,SOL_S0CKET,SO_SNDTIMEO,(char *)&nNetTimeout,sizeof(int));
            //接收時(shí)限
            setsockopt(socket,SOL_S0CKET,SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int));
            4.在send()的時(shí)候,返回的是實(shí)際發(fā)送出去的字節(jié)(同步)或發(fā)送到socket緩沖區(qū)的字節(jié)
            (異步);系統(tǒng)默認(rèn)的狀態(tài)發(fā)送和接收一次為8688字節(jié)(約為8.5K);在實(shí)際的過(guò)程中發(fā)送數(shù)據(jù)
            和接收數(shù)據(jù)量比較大,可以設(shè)置socket緩沖區(qū),而避免了send(),recv()不斷的循環(huán)收發(fā):
            // 接收緩沖區(qū)
            int nRecvBuf=32*1024;//設(shè)置為32K
            setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));
            //發(fā)送緩沖區(qū)
            int nSendBuf=32*1024;//設(shè)置為32K
            setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));
            5. 如果在發(fā)送數(shù)據(jù)的時(shí),希望不經(jīng)歷由系統(tǒng)緩沖區(qū)到socket緩沖區(qū)的拷貝而影響
            程序的性能:
            int nZero=0;
            setsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char *)&nZero,sizeof(nZero));
            6.同上在recv()完成上述功能(默認(rèn)情況是將socket緩沖區(qū)的內(nèi)容拷貝到系統(tǒng)緩沖區(qū)):
            int nZero=0;
            setsockopt(socket,SOL_S0CKET,SO_RCVBUF,(char *)&nZero,sizeof(int));
            7.一般在發(fā)送UDP數(shù)據(jù)報(bào)的時(shí)候,希望該socket發(fā)送的數(shù)據(jù)具有廣播特性:
            BOOL bBroadcast=TRUE;
            setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char*)&bBroadcast,sizeof(BOOL));
            8.在client連接服務(wù)器過(guò)程中,如果處于非阻塞模式下的socket在connect()的過(guò)程中可
            以設(shè)置connect()延時(shí),直到accpet()被呼叫(本函數(shù)設(shè)置只有在非阻塞的過(guò)程中有顯著的
            作用,在阻塞的函數(shù)調(diào)用中作用不大)
            BOOL bConditionalAccept=TRUE;
            setsockopt(s,SOL_SOCKET,SO_CONDITIONAL_ACCEPT,(const char*)&bConditionalAccept,sizeof(BOOL));
            9.如果在發(fā)送數(shù)據(jù)的過(guò)程中(send()沒(méi)有完成,還有數(shù)據(jù)沒(méi)發(fā)送)而調(diào)用了closesocket(),以前我們
            一般采取的措施是"從容關(guān)閉"shutdown(s,SD_BOTH),但是數(shù)據(jù)是肯定丟失了,如何設(shè)置讓程序滿足具體
            應(yīng)用的要求(即讓沒(méi)發(fā)完的數(shù)據(jù)發(fā)送出去后在關(guān)閉socket)?
            struct linger {
            u_short l_onoff;
            u_short l_linger;
            };
            linger m_sLinger;
            m_sLinger.l_onoff=1;//(在closesocket()調(diào)用,但是還有數(shù)據(jù)沒(méi)發(fā)送完畢的時(shí)候容許逗留)
            // 如果m_sLinger.l_onoff=0;則功能和2.)作用相同;
            m_sLinger.l_linger=5;//(容許逗留的時(shí)間為5秒)
            setsockopt(s,SOL_SOCKET,SO_LINGER,(const char*)&m_sLinger,sizeof(linger));
             
            設(shè)置套接口的選項(xiàng)。
               #include <winsock.h>
               int PASCAL FAR setsockopt( SOCKET s, int level, int optname,
               const char FAR* optval, int optlen);
               s:標(biāo)識(shí)一個(gè)套接口的描述字。
               level:選項(xiàng)定義的層次;目前僅支持SOL_SOCKET和IPPROTO_TCP層次。
               optname:需設(shè)置的選項(xiàng)。
               optval:指針,指向存放選項(xiàng)值的緩沖區(qū)。
               optlen:optval緩沖區(qū)的長(zhǎng)度。
            注釋?zhuān)?br />setsockopt()函數(shù)用于任意類(lèi)型、任意狀態(tài)套接口的設(shè)置選項(xiàng)值。盡管在不同協(xié)議層上存在選項(xiàng),但本函數(shù)僅定義了最高的“套接口”層次上的選項(xiàng)。選項(xiàng)影響套接口的操作,諸如加急數(shù)據(jù)是否在普通數(shù)據(jù)流中接收,廣播數(shù)據(jù)是否可以從套接口發(fā)送等等。
               有兩種套接口的選項(xiàng):一種是布爾型選項(xiàng),允許或禁止一種特性;另一種是整形或結(jié)構(gòu)選項(xiàng)。允許一個(gè)布爾型選項(xiàng),則將optval指向非零整形數(shù);禁止一個(gè)選項(xiàng)optval指向一個(gè)等于零的整形數(shù)。對(duì)于布爾型選項(xiàng),optlen應(yīng)等于sizeof(int);對(duì)其他選項(xiàng),optval指向包含所需選項(xiàng)的整形數(shù)或結(jié)構(gòu),而optlen則為整形數(shù)或結(jié)構(gòu)的長(zhǎng)度。SO_LINGER選項(xiàng)用于控制下述情況的行動(dòng):套接口上有排隊(duì)的待發(fā)送數(shù)據(jù),且 closesocket()調(diào)用已執(zhí)行。參見(jiàn)closesocket()函數(shù)中關(guān)于SO_LINGER選項(xiàng)對(duì)closesocket()語(yǔ)義的影響。應(yīng)用程序通過(guò)創(chuàng)建一個(gè)linger結(jié)構(gòu)來(lái)設(shè)置相應(yīng)的操作特性:
               struct linger {
            int l_onoff;
            int l_linger;
               };
               為了允許SO_LINGER,應(yīng)用程序應(yīng)將l_onoff設(shè)為非零,將l_linger設(shè)為零或需要的超時(shí)值(以秒為單位),然后調(diào)用setsockopt()。為了允許SO_DONTLINGER(亦即禁止SO_LINGER),l_onoff應(yīng)設(shè)為零,然后調(diào)用setsockopt()。
               缺省條件下,一個(gè)套接口不能與一個(gè)已在使用中的本地地址捆綁(參見(jiàn)bind())。但有時(shí)會(huì)需要“重用”地址。因?yàn)槊恳粋€(gè)連接都由本地地址和遠(yuǎn)端地址的組合唯一確定,所以只要遠(yuǎn)端地址不同,兩個(gè)套接口與一個(gè)地址捆綁并無(wú)大礙。為了通知WINDOWS套接口實(shí)現(xiàn)不要因?yàn)橐粋€(gè)地址已被一個(gè)套接口使用就不讓它與另一個(gè)套接口捆綁,應(yīng)用程序可在bind()調(diào)用前先設(shè)置SO_REUSEADDR選項(xiàng)。請(qǐng)注意僅在bind()調(diào)用時(shí)該選項(xiàng)才被解釋?zhuān)还蚀藷o(wú)需(但也無(wú)害)將一個(gè)不會(huì)共用地址的套接口設(shè)置該選項(xiàng),或者在bind()對(duì)這個(gè)或其他套接口無(wú)影響情況下設(shè)置或清除這一選項(xiàng)。
               一個(gè)應(yīng)用程序可以通過(guò)打開(kāi)SO_KEEPALIVE選項(xiàng),使得WINDOWS套接口實(shí)現(xiàn)在TCP連接情況下允許使用“保持活動(dòng)”包。一個(gè)WINDOWS套接口實(shí)現(xiàn)并不是必需支持“保持活動(dòng)”,但是如果支持的話,具體的語(yǔ)義將與實(shí)現(xiàn)有關(guān),應(yīng)遵守RFC1122“Internet主機(jī)要求-通訊層”中第 4.2.3.6節(jié)的規(guī)范。如果有關(guān)連接由于“保持活動(dòng)”而失效,則進(jìn)行中的任何對(duì)該套接口的調(diào)用都將以WSAENETRESET錯(cuò)誤返回,后續(xù)的任何調(diào)用將以WSAENOTCONN錯(cuò)誤返回。
               TCP_NODELAY選項(xiàng)禁止Nagle算法。Nagle算法通過(guò)將未確認(rèn)的數(shù)據(jù)存入緩沖區(qū)直到蓄足一個(gè)包一起發(fā)送的方法,來(lái)減少主機(jī)發(fā)送的零碎小數(shù)據(jù)包的數(shù)目。但對(duì)于某些應(yīng)用來(lái)說(shuō),這種算法將降低系統(tǒng)性能。所以TCP_NODELAY可用來(lái)將此算法關(guān)閉。應(yīng)用程序編寫(xiě)者只有在確切了解它的效果并確實(shí)需要的情況下,才設(shè)置TCP_NODELAY選項(xiàng),因?yàn)樵O(shè)置后對(duì)網(wǎng)絡(luò)性能有明顯的負(fù)面影響。TCP_NODELAY是唯一使用IPPROTO_TCP層的選項(xiàng),其他所有選項(xiàng)都使用SOL_SOCKET層。
               如果設(shè)置了SO_DEBUG選項(xiàng),WINDOWS套接口供應(yīng)商被鼓勵(lì)(但不是必需)提供輸出相應(yīng)的調(diào)試信息。但產(chǎn)生調(diào)試信息的機(jī)制以及調(diào)試信息的形式已超出本規(guī)范的討論范圍。
            setsockopt()支持下列選項(xiàng)。其中“類(lèi)型”表明optval所指數(shù)據(jù)的類(lèi)型。
            選項(xiàng)        類(lèi)型   意義
            SO_BROADCAST BOOL 允許套接口傳送廣播信息。
            SO_DEBUG BOOL 記錄調(diào)試信息。
            SO_DONTLINER BOOL 不要因?yàn)閿?shù)據(jù)未發(fā)送就阻塞關(guān)閉操作。設(shè)置本選項(xiàng)相當(dāng)于將SO_LINGER的l_onoff元素置為零。
            SO_DONTROUTE BOOL 禁止選徑;直接傳送。
            SO_KEEPALIVE BOOL 發(fā)送“保持活動(dòng)”包。
            SO_LINGER struct linger FAR*   如關(guān)閉時(shí)有未發(fā)送數(shù)據(jù),則逗留。
            SO_OOBINLINE BOOL 在常規(guī)數(shù)據(jù)流中接收帶外數(shù)據(jù)。
            SO_RCVBUF int 為接收確定緩沖區(qū)大小。
            SO_REUSEADDR BOOL 允許套接口和一個(gè)已在使用中的地址捆綁(參見(jiàn)bind())。
            SO_SNDBUF int 指定發(fā)送緩沖區(qū)大小。
            TCP_NODELAY BOOL 禁止發(fā)送合并的Nagle算法。
            setsockopt()不支持的BSD選項(xiàng)有:
            選項(xiàng)名    類(lèi)型 意義
            SO_ACCEPTCONN BOOL 套接口在監(jiān)聽(tīng)。
            SO_ERROR int 獲取錯(cuò)誤狀態(tài)并清除。
            SO_RCVLOWAT int 接收低級(jí)水印。
            SO_RCVTIMEO int 接收超時(shí)。
            SO_SNDLOWAT int 發(fā)送低級(jí)水印。
            SO_SNDTIMEO int 發(fā)送超時(shí)。
            SO_TYPE     int 套接口類(lèi)型。
            IP_OPTIONS    在IP頭中設(shè)置選項(xiàng)。
            返回值:
               若無(wú)錯(cuò)誤發(fā)生,setsockopt()返回0。否則的話,返回SOCKET_ERROR錯(cuò)誤,應(yīng)用程序可通過(guò)WSAGetLastError()獲取相應(yīng)錯(cuò)誤代碼。
            錯(cuò)誤代碼:
               WSANOTINITIALISED:在使用此API之前應(yīng)首先成功地調(diào)用WSAStartup()。
               WSAENETDOWN:WINDOWS套接口實(shí)現(xiàn)檢測(cè)到網(wǎng)絡(luò)子系統(tǒng)失效。
               WSAEFAULT:optval不是進(jìn)程地址空間中的一個(gè)有效部分。
               WSAEINPROGRESS:一個(gè)阻塞的WINDOWS套接口調(diào)用正在運(yùn)行中。
               WSAEINVAL:level值非法,或optval中的信息非法。
               WSAENETRESET:當(dāng)SO_KEEPALIVE設(shè)置后連接超時(shí)。
               WSAENOPROTOOPT:未知或不支持選項(xiàng)。其中,SOCK_STREAM類(lèi)型的套接口不支持SO_BROADCAST選項(xiàng),SOCK_DGRAM 類(lèi)型的套接口不支持SO_DONTLINGER 、SO_KEEPALIVE、SO_LINGER和SO_OOBINLINE選項(xiàng)。
               WSAENOTCONN:當(dāng)設(shè)置SO_KEEPALIVE后連接被復(fù)位。
               WSAENOTSOCK:描述字不是一個(gè)套接口。

            posted @ 2011-11-16 20:57 鄭興鋒 閱讀(414) | 評(píng)論 (0)編輯 收藏

            2011年3月22日

                   關(guān)于網(wǎng)游服務(wù)器的分類(lèi)和布局的問(wèn)題是在網(wǎng)絡(luò)游戲中比較關(guān)鍵的部分, 首先我們討論網(wǎng)絡(luò)游戲服務(wù)器的分類(lèi)問(wèn)題: 一般情況下游戲服務(wù)器分為: 登陸服務(wù)器, 網(wǎng)關(guān)服務(wù)器, 游戲服務(wù)器和數(shù)據(jù)庫(kù)服務(wù)器四類(lèi), 有的服務(wù)器可能是多臺(tái)并存的,如游戲服務(wù)器, 其中游戲服務(wù)器包括: 地圖服務(wù)器和邏輯服務(wù)器.
            下面這個(gè)圖描述了網(wǎng)關(guān)服務(wù)器和其他服務(wù)器之間的關(guān)系:
                 
            網(wǎng)關(guān)服務(wù)器的功能是將: 游戲服務(wù)器, 客戶(hù)端和數(shù)據(jù)庫(kù)服務(wù)器之間的消息進(jìn)行轉(zhuǎn)發(fā), 所以它負(fù)責(zé)管理客戶(hù)端的連接和服務(wù)端的連接, 并轉(zhuǎn)發(fā)他們之間的消息, 同時(shí)他還連接到數(shù)據(jù)庫(kù)服務(wù)器上,等需要數(shù)據(jù)讀取是對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作,并轉(zhuǎn)發(fā)給相應(yīng)的請(qǐng)求者.  (其實(shí)在對(duì)數(shù)據(jù)庫(kù)的連接這個(gè)問(wèn)題上,有游戲服務(wù)器來(lái)連接的,網(wǎng)關(guān)服務(wù)只負(fù)責(zé)轉(zhuǎn)發(fā)和簡(jiǎn)單的邏輯處理)。
                我們現(xiàn)在來(lái)討論下網(wǎng)關(guān)服務(wù)器是怎么實(shí)現(xiàn)的:網(wǎng)關(guān)服務(wù)器要管理兩個(gè)事情,一個(gè)是游戲服務(wù)器的連接,另一個(gè)玩家的連接。其實(shí)對(duì)于網(wǎng)關(guān)服務(wù)器而言,這兩個(gè)種類(lèi)型的連接差別,并不是很大,可以用一個(gè)網(wǎng)路模型來(lái)處理收到的消息,并將其轉(zhuǎn)發(fā)給相應(yīng)的接受者。
                游戲服務(wù)器中的地圖服務(wù)器:地圖服務(wù)器相對(duì)于網(wǎng)關(guān)服務(wù)器而言,它更像是一個(gè)客戶(hù)端,它在收到消息的時(shí)候處理消息,并將消息結(jié)果返回給網(wǎng)關(guān),網(wǎng)關(guān)把消息轉(zhuǎn)給相應(yīng)的連接。只是說(shuō)因?yàn)榈貓D服務(wù)器相對(duì)來(lái)說(shuō)是處理那些長(zhǎng)時(shí)間連接,需要不斷處理的邏輯的,如用戶(hù)的移動(dòng),狀態(tài),補(bǔ)給等,需要實(shí)時(shí)的消息處理。
                邏輯服務(wù)器的功能是實(shí)現(xiàn)如打怪,組隊(duì)等一些,不經(jīng)常交互的邏輯的。其實(shí)對(duì)于一組游戲服務(wù)器而言,大量的聊天信息也是很消耗系統(tǒng)資源的,有時(shí)候要單獨(dú)建立一個(gè)聊天服務(wù)器。
               數(shù)據(jù)庫(kù)服務(wù)器基本上是存放數(shù)據(jù)庫(kù)的,游戲服務(wù)器,邏輯服務(wù)器,在需要是讀取數(shù)據(jù),進(jìn)行邏輯處理。

               
              














             

            posted @ 2011-03-22 17:38 鄭興鋒 閱讀(705) | 評(píng)論 (0)編輯 收藏

            2011年2月15日

            Windows系統(tǒng)編程之進(jìn)程間通信
            北極星2003 當(dāng)前離線


            Windows 的IPC(進(jìn)程間通信)機(jī)制主要是異步管道和命名管道。(至于其他的IPC方式,例如內(nèi)存映射、郵槽等這里就不介紹了)
            管道(pipe)是用于進(jìn)程間通信的共享內(nèi)存區(qū)域。創(chuàng)建管道的進(jìn)程稱(chēng)為管道服務(wù)器,而連接到這個(gè)管道的進(jìn)程稱(chēng)為管道客戶(hù)端。一個(gè)進(jìn)程向管道寫(xiě)入信息,而另外一個(gè)進(jìn)程從管道讀取信息。
            異步管道是基于字符和半雙工的(即單向),一般用于程序輸入輸出的重定向;命名管道則強(qiáng)大地多,它們是面向消息和全雙工的,同時(shí)還允許網(wǎng)絡(luò)通信,用于創(chuàng)建客戶(hù)端/服務(wù)器系統(tǒng)。
            一、異步管道(實(shí)現(xiàn)比較簡(jiǎn)單,直接通過(guò)實(shí)例來(lái)講解)
            實(shí)驗(yàn)?zāi)繕?biāo):當(dāng)前有sample.cpp, sample.exe, sample.in這三個(gè)文件,sample.exe為sample.cpp的執(zhí)行程序,sample.cpp只是一個(gè)簡(jiǎn)單的程序示例(簡(jiǎn)單求和),如下:
            代碼:
            #include <iostream.h>
            int main()
            {
              int a, b ;
              while ( cin >> a >> b && ( a || b ) )
                cout << a + b << endl ;
              return 0;
            }
            
            Sample.in文件是輸入文件,內(nèi)容:
            32 433
            542 657
            0 0
            要求根據(jù)sample.exe和它的輸入數(shù)據(jù),把輸出數(shù)據(jù)重定向到sample.out
            流程分析:實(shí)際這個(gè)實(shí)驗(yàn)中包含兩個(gè)部分,把輸入數(shù)據(jù)重定向到sample.exe 和把輸出數(shù)據(jù)重定向到sample.out。在命令行下可以很簡(jiǎn)單的實(shí)現(xiàn)這個(gè)功能“sample <sample.in >sample.out”,這個(gè)命令也是利用管道特性實(shí)現(xiàn)的,現(xiàn)在我們就根據(jù)異步管道的實(shí)現(xiàn)原理自己來(lái)實(shí)現(xiàn)這個(gè)功能。
            管道是基于半雙工(單向)的,這里有兩個(gè)重定向的過(guò)程,顯然需要?jiǎng)?chuàng)建兩個(gè)管道,下面給出流程圖:
             
            異步管道實(shí)現(xiàn)的流程圖說(shuō)明:
            1)。父進(jìn)程是我們需要實(shí)現(xiàn)的,其中需要?jiǎng)?chuàng)建管道A,管道B,和子進(jìn)程,整個(gè)實(shí)現(xiàn)流程分為4個(gè)操作。
            2)。管道A:輸入管道
            3)。管道B:輸出管道
            4)。操作A:把輸入文件sample.in的數(shù)據(jù)寫(xiě)入輸入管道(管道A)
            5)。操作B:子進(jìn)程從輸入管道中讀取數(shù)據(jù),作為該進(jìn)程的加工原料。通常,程序的輸入數(shù)據(jù)由標(biāo)準(zhǔn)的輸入設(shè)備輸入,這里實(shí)現(xiàn)輸入重定向,即把輸入管道作為輸入設(shè)備。
            6)。操作C:子進(jìn)程把加工后的成品(輸出數(shù)據(jù))輸出到輸出管道。通常,程序的輸出數(shù)據(jù)會(huì)輸出到標(biāo)準(zhǔn)的輸出設(shè)備,一般為屏幕,這里實(shí)現(xiàn)輸出重定向,即把輸出管道作為輸出設(shè)備。
            7)。操作D:把輸出管道的數(shù)據(jù)寫(xiě)入輸出文件
            需要注意的是,管道的本質(zhì)只是一個(gè)共享的內(nèi)存區(qū)域。這個(gè)實(shí)驗(yàn)中,管道區(qū)域處于父進(jìn)程的地址空間中,父進(jìn)程的作用是提供環(huán)境和資源,并協(xié)調(diào)子進(jìn)程進(jìn)行加工。
            程序源碼:
            代碼:
            #include <windows.h> 
            #include <iostream.h>
            const int BUFSIZE = 4096 ; 
            HANDLE  hChildStdinRd, hChildStdinWr, hChildStdinWrDup, 
                   hChildStdoutRd,hChildStdoutWr,hChildStdoutRdDup, 
                hSaveStdin,    hSaveStdout; 
            BOOL CreateChildProcess(LPTSTR); 
            VOID WriteToPipe(LPTSTR); 
            VOID ReadFromPipe(LPTSTR); 
            VOID ErrorExit(LPTSTR); 
            VOID ErrMsg(LPTSTR, BOOL); 
            void main( int argc, char *argv[] ) 
            {  
              // 處理輸入?yún)?shù)
              if ( argc != 4 )
                return ;
              // 分別用來(lái)保存命令行,輸入文件名(CPP/C),輸出文件名(保存編譯信息)
              LPTSTR lpProgram = new char[ strlen(argv[1]) ] ;
              strcpy ( lpProgram, argv[1] ) ;
              LPTSTR lpInputFile = new char[ strlen(argv[2]) ];
              strcpy ( lpInputFile, argv[2] ) ;
              LPTSTR lpOutputFile = new char[ strlen(argv[3]) ] ;
              strcpy ( lpOutputFile, argv[3] ) ;    
              
              SECURITY_ATTRIBUTES saAttr; 
              saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
              saAttr.bInheritHandle = TRUE; 
              saAttr.lpSecurityDescriptor = NULL; 
               
              /************************************************
               *    redirecting child process's STDOUT  *
               ************************************************/
              hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
              
              if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) 
                ErrorExit("Stdout pipe creation failed\n"); 
                
              if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr)) 
                ErrorExit("Redirecting STDOUT failed"); 
              
              BOOL fSuccess = DuplicateHandle(
                GetCurrentProcess(), 
                hChildStdoutRd,
                    GetCurrentProcess(), 
                &hChildStdoutRdDup ,
                0,
                    FALSE,
                    DUPLICATE_SAME_ACCESS);
                if( !fSuccess )
                    ErrorExit("DuplicateHandle failed");
                CloseHandle(hChildStdoutRd);
              
              /************************************************
               *    redirecting child process's STDIN    *
               ************************************************/
              hSaveStdin = GetStdHandle(STD_INPUT_HANDLE); 
              if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) 
                ErrorExit("Stdin pipe creation failed\n"); 
              
              if (! SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd)) 
                ErrorExit("Redirecting Stdin failed"); 
              
              fSuccess = DuplicateHandle(
                GetCurrentProcess(), 
                hChildStdinWr, 
                GetCurrentProcess(),
                &hChildStdinWrDup, 
                0, 
                FALSE,                 
                DUPLICATE_SAME_ACCESS); 
              if (! fSuccess) 
                ErrorExit("DuplicateHandle failed"); 
              CloseHandle(hChildStdinWr);   
              /************************************************
               *      創(chuàng)建子進(jìn)程(即啟動(dòng)SAMPLE.EXE)    *
               ************************************************/
              fSuccess = CreateChildProcess( lpProgram );
              if ( !fSuccess ) 
                ErrorExit("Create process failed"); 
              
              // 父進(jìn)程輸入輸出流的還原設(shè)置
              if (! SetStdHandle(STD_INPUT_HANDLE, hSaveStdin)) 
                ErrorExit("Re-redirecting Stdin failed\n"); 
              if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout)) 
                ErrorExit("Re-redirecting Stdout failed\n"); 
              WriteToPipe( lpInputFile ) ;
              ReadFromPipe( lpOutputFile ); 
                      delete lpProgram ;
                      delete lpInputFile ;
                      delete lpOutputFile ;
            } 
            BOOL CreateChildProcess( LPTSTR lpProgram ) 
            { 
              PROCESS_INFORMATION piProcInfo; 
              STARTUPINFO siStartInfo;
              BOOL bFuncRetn = FALSE; 
              
              ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
              ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
              siStartInfo.cb = sizeof(STARTUPINFO); 
              
              bFuncRetn = CreateProcess ( NULL, lpProgram, NULL, NULL, TRUE, \
                            0, NULL, NULL, &siStartInfo, &piProcInfo);
              if (bFuncRetn == 0) 
              {
                ErrorExit("CreateProcess failed\n");
                return 0;
              } 
              else 
              {
                CloseHandle(piProcInfo.hProcess);
                CloseHandle(piProcInfo.hThread);
                return bFuncRetn;
              }
            }
            VOID WriteToPipe( LPTSTR lpInputFile ) 
            { 
              HANDLE hInputFile = CreateFile(lpInputFile, GENERIC_READ, 0, NULL, 
                OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); 
              if (hInputFile == INVALID_HANDLE_VALUE) 
                return ;
              BOOL fSuccess ;
              DWORD dwRead, dwWritten; 
              CHAR chBuf[BUFSIZE] = {0} ; 
              
              for (;;) 
              { 
                fSuccess = ReadFile( hInputFile, chBuf, BUFSIZE, &dwRead, NULL) ;
                if ( !fSuccess || dwRead == 0)
                  break; 
                fSuccess = WriteFile( hChildStdinWrDup, chBuf, dwRead, &dwWritten, NULL) ;
                if ( !fSuccess ) 
                  break; 
              } 
                
              if (! CloseHandle(hChildStdinWrDup)) 
                ErrorExit("Close pipe failed\n"); 
              CloseHandle ( hInputFile ) ;
            } 
            VOID ReadFromPipe( LPTSTR lpOutputFile ) 
            { 
              HANDLE hOutputFile = CreateFile( lpOutputFile, GENERIC_READ|GENERIC_WRITE, 
                FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 
              if (hOutputFile == INVALID_HANDLE_VALUE) 
                return ;
              BOOL fSuccess ;
              DWORD dwRead, dwWritten; 
              CHAR chBuf[BUFSIZE] = { 0 }; 
              
              if (!CloseHandle(hChildStdoutWr)) 
                ErrorExit("Closing handle failed"); 
              
              for (;;) 
              { 
                fSuccess = ReadFile( hChildStdoutRdDup, chBuf, BUFSIZE, &dwRead, NULL) ;
                if( !fSuccess || dwRead == 0) 
                {
                  break; 
                }
                fSuccess = WriteFile( hOutputFile, chBuf, dwRead, &dwWritten, NULL) ;
                if ( !fSuccess ) 
                  break; 
              } 
              CloseHandle ( hOutputFile ) ;
            } 
            VOID ErrorExit (LPTSTR lpszMessage) 
            { 
              MessageBox( 0, lpszMessage, 0, 0 ); 
            }
            
            二、命名管道
            命名管道具有以下幾個(gè)特征:
            (1)命名管道是雙向的,所以?xún)蓚€(gè)進(jìn)程可以通過(guò)同一管道進(jìn)行交互。
            (2)命名管道不但可以面向字節(jié)流,還可以面向消息,所以讀取進(jìn)程可以讀取寫(xiě)進(jìn)程發(fā)送的不同長(zhǎng)度的消息。
            (3)多個(gè)獨(dú)立的管道實(shí)例可以用一個(gè)名稱(chēng)來(lái)命名。例如幾個(gè)客戶(hù)端可以使用名稱(chēng)相同的管道與同一個(gè)服務(wù)器進(jìn)行并發(fā)通信。
            (4)命名管道可以用于網(wǎng)絡(luò)間兩個(gè)進(jìn)程的通信,而其實(shí)現(xiàn)的過(guò)程與本地進(jìn)程通信完全一致。
            實(shí)驗(yàn)?zāi)繕?biāo):在客戶(hù)端輸入數(shù)據(jù)a和b,然后發(fā)送到服務(wù)器并計(jì)算a+b,然后把計(jì)算結(jié)果發(fā)送到客戶(hù)端。可以多個(gè)客戶(hù)端與同一個(gè)服務(wù)器并行通信。
            界面設(shè)計(jì):
             http://bbs.pediy.com/upload/2006/41/image/namedpipe.gif 
            難點(diǎn)所在:
            實(shí)現(xiàn)的過(guò)程比較簡(jiǎn)單,但有一個(gè)難點(diǎn)。原本當(dāng)服務(wù)端使用ConnectNamedPipe函數(shù)后,如果有客戶(hù)端連接,就可以直接進(jìn)行交互。原來(lái)我在實(shí)現(xiàn)過(guò)程中,當(dāng)管道空閑時(shí),管道的線程函數(shù)會(huì)無(wú)限(INFINITE)阻塞。若現(xiàn)在需要停止服務(wù),就必須結(jié)束所有的線程,TernimateThread可以作為一個(gè)結(jié)束線程的方法,但我基本不用這個(gè)函數(shù)。一旦使用這個(gè)函數(shù)之后,目標(biāo)線程就會(huì)立即結(jié)束,但如果此時(shí)的目標(biāo)線程正在操作互斥資源、內(nèi)核調(diào)用、或者是操作共享DLL的全局變量,可能會(huì)出現(xiàn)互斥資源無(wú)法釋放、內(nèi)核異常等現(xiàn)象。這里我用重疊I/0來(lái)解決這個(gè)問(wèn)題,在創(chuàng)建PIPE時(shí)使用FILE_FLAG_OVERLAPPED標(biāo)志,這樣使用ConnectNamedPipe后會(huì)立即返回,但線程的阻塞由等待函數(shù)WaitForSingleObject來(lái)實(shí)現(xiàn),等待OVERLAPPED結(jié)構(gòu)的事件對(duì)象被設(shè)置。
            客戶(hù)端主要代碼:
            代碼:
            void CMyDlg::OnSubmit() 
            {
              // 打開(kāi)管道
              HANDLE hPipe = CreateFile("\\\\.\\Pipe\\NamedPipe", GENERIC_READ | GENERIC_WRITE, \
                0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL) ;
              if ( hPipe == INVALID_HANDLE_VALUE )
              {
                this->MessageBox ( "打開(kāi)管道失敗,服務(wù)器尚未啟動(dòng),或者客戶(hù)端數(shù)量過(guò)多" ) ;
                return ;
              }
              DWORD nReadByte, nWriteByte ;
              char szBuf[1024] = {0} ;
              // 把兩個(gè)整數(shù)(a,b)格式化為字符串
              sprintf ( szBuf, "%d %d", this->nFirst, this->nSecond ) ;
              // 把數(shù)據(jù)寫(xiě)入管道
              WriteFile ( hPipe, szBuf, strlen(szBuf), &nWriteByte, NULL ) ;
              memset ( szBuf, 0, sizeof(szBuf) ) ;
              // 讀取服務(wù)器的反饋信息
              ReadFile ( hPipe, szBuf, 1024, &nReadByte, NULL ) ;
              // 把返回信息格式化為整數(shù)
              sscanf ( szBuf, "%d", &(this->nResValue) ) ;
              this->UpdateData ( false ) ;
              CloseHandle ( hPipe ) ;
            }
            
            服務(wù)端主要代碼:
            代碼:
            // 啟動(dòng)服務(wù)
            void CMyDlg::OnStart() 
            {
              CString lpPipeName = "\\\\.\\Pipe\\NamedPipe" ;
              for ( UINT i = 0; i < nMaxConn; i++ )
              {
                // 創(chuàng)建管道實(shí)例
                PipeInst[i].hPipe =  CreateNamedPipe ( lpPipeName, PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, \
                      PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_WAIT, nMaxConn, 0, 0, 1000, NULL ) ;
                if ( PipeInst[i].hPipe == INVALID_HANDLE_VALUE )
                {
                  DWORD dwErrorCode = GetLastError () ;
                  this->MessageBox ( "創(chuàng)建管道錯(cuò)誤!" ) ;
                  return ;
                }
                // 為每個(gè)管道實(shí)例創(chuàng)建一個(gè)事件對(duì)象,用于實(shí)現(xiàn)重疊IO
                PipeInst[i].hEvent  =  CreateEvent ( NULL, false, false, false ) ;
                // 為每個(gè)管道實(shí)例分配一個(gè)線程,用于響應(yīng)客戶(hù)端的請(qǐng)求
                PipeInst[i].hTread = AfxBeginThread ( ServerThread, &PipeInst[i], THREAD_PRIORITY_NORMAL ) ;
              }
              
              this->SetWindowText ( "命名管道實(shí)例之服務(wù)器(運(yùn)行)" ) ;
              this->MessageBox ( "服務(wù)啟動(dòng)成功" ) ;
            }
            // 停止服務(wù)
            void CMyDlg::OnStop() 
            {
              DWORD dwNewMode = PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_NOWAIT ;
              for ( UINT i = 0; i < nMaxConn; i++ )
              {
                SetEvent ( PipeInst[i].hEvent ) ;
                CloseHandle ( PipeInst[i].hTread ) ;
                CloseHandle ( PipeInst[i].hPipe ) ;
              }
                
              this->SetWindowText ( "命名管道實(shí)例之服務(wù)器" ) ;
              this->MessageBox ( "停止啟動(dòng)成功" ) ;
            }
            // 線程服務(wù)函數(shù)
            UINT ServerThread ( LPVOID lpParameter )
            {
              DWORD  nReadByte = 0, nWriteByte = 0, dwByte = 0 ;  
              char  szBuf[MAX_BUFFER_SIZE] = {0} ;
              PIPE_INSTRUCT  CurPipeInst = *(PIPE_INSTRUCT*)lpParameter ;
              OVERLAPPED OverLapStruct = { 0, 0, 0, 0, CurPipeInst.hEvent } ;
              while ( true )
              {
                memset ( szBuf, 0, sizeof(szBuf) ) ;  
                // 命名管道的連接函數(shù),等待客戶(hù)端的連接(只針對(duì)NT)
                ConnectNamedPipe ( CurPipeInst.hPipe, &OverLapStruct ) ;
                // 實(shí)現(xiàn)重疊I/0,等待OVERLAPPED結(jié)構(gòu)的事件對(duì)象
                WaitForSingleObject ( CurPipeInst.hEvent, INFINITE ) ;
                // 檢測(cè)I/0是否已經(jīng)完成,如果未完成,意味著該事件對(duì)象是人工設(shè)置,即服務(wù)需要停止
                if ( !GetOverlappedResult ( CurPipeInst.hPipe, &OverLapStruct, &dwByte, true ) )
                  break ;
                // 從管道中讀取客戶(hù)端的請(qǐng)求信息
                if ( !ReadFile ( CurPipeInst.hPipe, szBuf, MAX_BUFFER_SIZE, &nReadByte, NULL ) )
                {
                  MessageBox ( 0, "讀取管道錯(cuò)誤!", 0, 0 ) ;
                  break ;
                }
                
                int a, b ;
                sscanf ( szBuf, "%d %d", &a, &b ) ;
                pMyDlg->nFirst    = a ;
                pMyDlg->nSecond    = b ;
                pMyDlg->nResValue  = a + b ;
                memset ( szBuf, 0, sizeof(szBuf) ) ;
                sprintf ( szBuf, "%d", pMyDlg->nResValue ) ;
                // 把反饋信息寫(xiě)入管道
                WriteFile ( CurPipeInst.hPipe, szBuf, strlen(szBuf), &nWriteByte, NULL ) ;
                pMyDlg->SetDlgItemInt ( IDC_FIRST, a, true ) ;
                pMyDlg->SetDlgItemInt ( IDC_SECOND, b, true ) ;
                pMyDlg->SetDlgItemInt ( IDC_RESULT, pMyDlg->nResValue, true ) ;
                // 斷開(kāi)客戶(hù)端的連接,以便等待下一客戶(hù)的到來(lái)
                DisconnectNamedPipe ( CurPipeInst.hPipe ) ;
              }
              return 0 ;
            }
            

            posted @ 2011-02-15 12:30 鄭興鋒 閱讀(791) | 評(píng)論 (0)編輯 收藏

            2010年11月4日

            setsockopt()

            目錄

            簡(jiǎn)述:
            注釋?zhuān)?/font>
            返回值:
            用法

            簡(jiǎn)述:

              設(shè)置套接口的選項(xiàng)。
              #include <winsock.h>
              int PASCAL FAR setsockopt( SOCKET s, int level, int optname,
              const char FAR* optval, int optlen);
              s:標(biāo)識(shí)一個(gè)套接口的描述字。
              level:選項(xiàng)定義的層次;目前僅支持SOL_SOCKET和IPPROTO_TCP層次。
              optname:需設(shè)置的選項(xiàng)。
              optval:指針,指向存放選項(xiàng)值的緩沖區(qū)。
              optlen:optval緩沖區(qū)的長(zhǎng)度。

            注釋?zhuān)?/h2>   setsockopt()函數(shù)用于任意類(lèi)型、任意狀態(tài)套接口的設(shè)置選項(xiàng)值。盡管在不同協(xié)議層上存在選項(xiàng),但本函數(shù)僅定義了最高的“套接口”層次上的選項(xiàng)。選項(xiàng)影響套接口的操作,諸如加急數(shù)據(jù)是否在普通數(shù)據(jù)流中接收,廣播數(shù)據(jù)是否可以從套接口發(fā)送等等。
              有兩種套接口的選項(xiàng):一種是布爾型選項(xiàng),允許或禁止一種特性;另一種是整形或結(jié)構(gòu)選項(xiàng)。允許一個(gè)布爾型選項(xiàng),則將optval指向非零整形數(shù);禁止一個(gè)選項(xiàng)optval指向一個(gè)等于零的整形數(shù)。對(duì)于布爾型選項(xiàng),optlen應(yīng)等于sizeof(int);對(duì)其他選項(xiàng),optval指向包含所需選項(xiàng)的整形數(shù)或結(jié)構(gòu),而optlen則為整形數(shù)或結(jié)構(gòu)的長(zhǎng)度。SO_LINGER選項(xiàng)用于控制下述情況的行動(dòng):套接口上有排隊(duì)的待發(fā)送數(shù)據(jù),且closesocket()調(diào)用已執(zhí)行。參見(jiàn)closesocket()函數(shù)中關(guān)于SO_LINGER選項(xiàng)對(duì)closesocket()語(yǔ)義的影響。應(yīng)用程序通過(guò)創(chuàng)建一個(gè)linger結(jié)構(gòu)來(lái)設(shè)置相應(yīng)的操作特性:
              struct linger {
              int l_onoff;
              int l_linger;
              };
              為了允許SO_LINGER,應(yīng)用程序應(yīng)將l_onoff設(shè)為非零,將l_linger設(shè)為零或需要的超時(shí)值(以秒為單位),然后調(diào)用setsockopt()。為了允許SO_DONTLINGER(亦即禁止SO_LINGER),l_onoff應(yīng)設(shè)為零,然后調(diào)用setsockopt()。
              缺省條件下,一個(gè)套接口不能與一個(gè)已在使用中的本地地址捆綁(參見(jiàn)bind())。但有時(shí)會(huì)需要“重用”地址。因?yàn)槊恳粋€(gè)連接都由本地地址和遠(yuǎn)端地址的組合唯一確定,所以只要遠(yuǎn)端地址不同,兩個(gè)套接口與一個(gè)地址捆綁并無(wú)大礙。為了通知WINDOWS套接口實(shí)現(xiàn)不要因?yàn)橐粋€(gè)地址已被一個(gè)套接口使用就不讓它與另一個(gè)套接口捆綁,應(yīng)用程序可在bind()調(diào)用前先設(shè)置SO_REUSEADDR選項(xiàng)。請(qǐng)注意僅在bind()調(diào)用時(shí)該選項(xiàng)才被解釋?zhuān)还蚀藷o(wú)需(但也無(wú)害)將一個(gè)不會(huì)共用地址的套接口設(shè)置該選項(xiàng),或者在bind()對(duì)這個(gè)或其他套接口無(wú)影響情況下設(shè)置或清除這一選項(xiàng)。
              一個(gè)應(yīng)用程序可以通過(guò)打開(kāi)SO_KEEPALIVE選項(xiàng),使得WINDOWS套接口實(shí)現(xiàn)在TCP連接情況下允許使用“保持活動(dòng)”包。一個(gè)WINDOWS套接口實(shí)現(xiàn)并不是必需支持“保持活動(dòng)”,但是如果支持的話,具體的語(yǔ)義將與實(shí)現(xiàn)有關(guān),應(yīng)遵守RFC1122“Internet主機(jī)要求-通訊層”中第4.2.3.6節(jié)的規(guī)范。如果有關(guān)連接由于“保持活動(dòng)”而失效,則進(jìn)行中的任何對(duì)該套接口的調(diào)用都將以WSAENETRESET錯(cuò)誤返回,后續(xù)的任何調(diào)用將以WSAENOTCONN錯(cuò)誤返回。
              TCP_NODELAY選項(xiàng)禁止Nagle算法。Nagle算法通過(guò)將未確認(rèn)的數(shù)據(jù)存入緩沖區(qū)直到蓄足一個(gè)包一起發(fā)送的方法,來(lái)減少主機(jī)發(fā)送的零碎小數(shù)據(jù)包的數(shù)目。但對(duì)于某些應(yīng)用來(lái)說(shuō),這種算法將降低系統(tǒng)性能。所以TCP_NODELAY可用來(lái)將此算法關(guān)閉。應(yīng)用程序編寫(xiě)者只有在確切了解它的效果并確實(shí)需要的情況下,才設(shè)置TCP_NODELAY選項(xiàng),因?yàn)樵O(shè)置后對(duì)網(wǎng)絡(luò)性能有明顯的負(fù)面影響。TCP_NODELAY是唯一使用IPPROTO_TCP層的選項(xiàng),其他所有選項(xiàng)都使用SOL_SOCKET層。
              如果設(shè)置了SO_DEBUG選項(xiàng),WINDOWS套接口供應(yīng)商被鼓勵(lì)(但不是必需)提供輸出相應(yīng)的調(diào)試信息。但產(chǎn)生調(diào)試信息的機(jī)制以及調(diào)試信息的形式已超出本規(guī)范的討論范圍。
              setsockopt()支持下列選項(xiàng)。其中“類(lèi)型”表明optval所指數(shù)據(jù)的類(lèi)型。
              選項(xiàng) 類(lèi)型 意義
              SO_BROADCAST BOOL 允許套接口傳送廣播信息。
              SO_DEBUG BOOL 記錄調(diào)試信息。
              SO_DONTLINER BOOL 不要因?yàn)閿?shù)據(jù)未發(fā)送就阻塞關(guān)閉操作。設(shè)置本選項(xiàng)相當(dāng)于將SO_LINGER的l_onoff元素置為零。
              SO_DONTROUTE BOOL 禁止選徑;直接傳送。
              SO_KEEPALIVE BOOL 發(fā)送“保持活動(dòng)”包。
              SO_LINGER struct linger FAR* 如關(guān)閉時(shí)有未發(fā)送數(shù)據(jù),則逗留。
              SO_OOBINLINE BOOL 在常規(guī)數(shù)據(jù)流中接收帶外數(shù)據(jù)。
              SO_RCVBUF int 為接收確定緩沖區(qū)大小。
              SO_REUSEADDR BOOL 允許套接口和一個(gè)已在使用中的地址捆綁(參見(jiàn)bind())。
              SO_SNDBUF int 指定發(fā)送緩沖區(qū)大小。
              TCP_NODELAY BOOL 禁止發(fā)送合并的Nagle算法。
              setsockopt()不支持的BSD選項(xiàng)有:
              選項(xiàng)名 類(lèi)型 意義
              SO_ACCEPTCONN BOOL 套接口在監(jiān)聽(tīng)。
              SO_ERROR int 獲取錯(cuò)誤狀態(tài)并清除。
              SO_RCVLOWAT int 接收低級(jí)水印。
              SO_RCVTIMEO int 接收超時(shí)。
              SO_SNDLOWAT int 發(fā)送低級(jí)水印。
              SO_SNDTIMEO int 發(fā)送超時(shí)。
              SO_TYPE int 套接口類(lèi)型。
              IP_OPTIONS 在IP頭中設(shè)置選項(xiàng)。

            返回值:

              若無(wú)錯(cuò)誤發(fā)生,setsockopt()返回0。否則的話,返回SOCKET_ERROR錯(cuò)誤,應(yīng)用程序可通過(guò)WSAGetLastError()獲取相應(yīng)錯(cuò)誤代碼。
              錯(cuò)誤代碼:
              WSANOTINITIALISED:在使用此API之前應(yīng)首先成功地調(diào)用WSAStartup()。
              WSAENETDOWN:WINDOWS套接口實(shí)現(xiàn)檢測(cè)到網(wǎng)絡(luò)子系統(tǒng)失效。
              WSAEFAULT:optval不是進(jìn)程地址空間中的一個(gè)有效部分。
              WSAEINPROGRESS:一個(gè)阻塞的WINDOWS套接口調(diào)用正在運(yùn)行中。
              WSAEINVAL:level值非法,或optval中的信息非法。
              WSAENETRESET:當(dāng)SO_KEEPALIVE設(shè)置后連接超時(shí)。
              WSAENOPROTOOPT:未知或不支持選項(xiàng)。其中,SOCK_STREAM類(lèi)型的套接口不支持SO_BROADCAST選項(xiàng),SOCK_DGRAM類(lèi)型的套接口不支持SO_DONTLINGER 、SO_KEEPALIVE、SO_LINGER和SO_OOBINLINE選項(xiàng)。
              WSAENOTCONN:當(dāng)設(shè)置SO_KEEPALIVE后連接被復(fù)位。
              WSAENOTSOCK:描述字不是一個(gè)套接口。

            用法

              1.設(shè)置調(diào)用closesocket()后,仍可繼續(xù)重用該socket。調(diào)用closesocket()一般不會(huì)立即關(guān)閉socket,而經(jīng)歷TIME_WAIT的過(guò)程。
              BOOL bReuseaddr = TRUE;
              setsockopt( s, SOL_SOCKET, SO_REUSEADDR, ( const char* )&bReuseaddr, sizeof( BOOL ) );
              2. 如果要已經(jīng)處于連接狀態(tài)的soket在調(diào)用closesocket()后強(qiáng)制關(guān)閉,不經(jīng)歷TIME_WAIT的過(guò)程:
              BOOL bDontLinger = FALSE;
              setsockopt( s, SOL_SOCKET, SO_DONTLINGER, ( const char* )&bDontLinger, sizeof( BOOL ) );
              3.在send(),recv()過(guò)程中有時(shí)由于網(wǎng)絡(luò)狀況等原因,收發(fā)不能預(yù)期進(jìn)行,可以設(shè)置收發(fā)時(shí)限:
              int nNetTimeout = 1000; //1秒
              //發(fā)送時(shí)限
              setsockopt( socket, SOL_SOCKET, SO_SNDTIMEO, ( char * )&nNetTimeout, sizeof( int ) );
              //接收時(shí)限
              setsockopt( socket, SOL_SOCKET, SO_RCVTIMEO, ( char * )&nNetTimeout, sizeof( int ) );
              4.在send()的時(shí)候,返回的是實(shí)際發(fā)送出去的字節(jié)(同步)或發(fā)送到socket緩沖區(qū)的字節(jié)(異步);系統(tǒng)默認(rèn)的狀態(tài)發(fā)送和接收一次為8688字節(jié)(約
              為8.5K);在實(shí)際的過(guò)程中如果發(fā)送或是接收的數(shù)據(jù)量比較大,可以設(shè)置socket緩沖區(qū),避免send(),recv()不斷的循環(huán)收發(fā):
              // 接收緩沖區(qū)
              int nRecvBuf = 32 * 1024; //設(shè)置為32K
              setsockopt( s, SOL_SOCKET, SO_RCVBUF, ( const char* )&nRecvBuf, sizeof( int ) );
              //發(fā)送緩沖區(qū)
              int nSendBuf = 32*1024; //設(shè)置為32K
              setsockopt( s, SOL_SOCKET, SO_SNDBUF, ( const char* )&nSendBuf, sizeof( int ) );
              5.在發(fā)送數(shù)據(jù)的時(shí),不執(zhí)行由系統(tǒng)緩沖區(qū)到socket緩沖區(qū)的拷貝,以提高程序的性能:
              int nZero = 0;
              setsockopt( socket, SOL_S0CKET, SO_SNDBUF, ( char * )&nZero, sizeof( nZero ) );
              6.在接收數(shù)據(jù)時(shí),不執(zhí)行將socket緩沖區(qū)的內(nèi)容拷貝到系統(tǒng)緩沖區(qū):
              int nZero = 0;
              setsockopt( s, SOL_S0CKET, SO_RCVBUF, ( char * )&nZero, sizeof( int ) );
              7.一般在發(fā)送UDP數(shù)據(jù)報(bào)的時(shí)候,希望該socket發(fā)送的數(shù)據(jù)具有廣播特性:
              BOOL bBroadcast = TRUE;
              setsockopt( s, SOL_SOCKET, SO_BROADCAST, ( const char* )&bBroadcast, sizeof( BOOL ) );
              8.在client連接服務(wù)器過(guò)程中,如果處于非阻塞模式下的socket在connect()的過(guò)程中可以設(shè)置connect()延時(shí),直到accpet()被調(diào)用(此設(shè)置只
              有在非阻塞的過(guò)程中有顯著的作用,在阻塞的函數(shù)調(diào)用中作用不大)
              BOOL bConditionalAccept = TRUE;
              setsockopt( s, SOL_SOCKET, SO_CONDITIONAL_ACCEPT, ( const char* )&bConditionalAccept, sizeof( BOOL ) );
              9.如果在發(fā)送數(shù)據(jù)的過(guò)程中send()沒(méi)有完成,還有數(shù)據(jù)沒(méi)發(fā)送,而調(diào)用了closesocket(),以前一般采取的措施是shutdown(s,SD_BOTH),但是數(shù)
              據(jù)將會(huì)丟失。
              某些具體程序要求待未發(fā)送完的數(shù)據(jù)發(fā)送出去后再關(guān)閉socket,可通過(guò)設(shè)置讓程序滿足要求:
              struct linger {
              u_short l_onoff;
              u_short l_linger;
              };
              linger m_sLinger;
              m_sLinger.l_onoff = 1; //在調(diào)用closesocket()時(shí)還有數(shù)據(jù)未發(fā)送完,允許等待
              // 若m_sLinger.l_onoff=0;則調(diào)用closesocket()后強(qiáng)制關(guān)閉
              m_sLinger.l_linger = 5; //設(shè)置等待時(shí)間為5秒
              setsockopt( s, SOL_SOCKET, SO_LINGER, ( const char* )&m_sLinger, sizeof( linger ) );

            posted @ 2010-11-04 14:32 鄭興鋒 閱讀(623) | 評(píng)論 (0)編輯 收藏

            控制套接口的模式。   
            #include <winsock.h>   int PASCAL FAR ioctlsocket( SOCKET s, long cmd, u_long FAR* argp);   
            s:一個(gè)標(biāo)識(shí)套接口的描述字。   
            cmd:對(duì)套接口s的操作命令。   
            argp:指向cmd命令所帶參數(shù)的指針。   
            注釋?zhuān)?  本函數(shù)可用于任一狀態(tài)的任一套接口。它用于獲取與套接口相關(guān)的操作參數(shù),而與具體協(xié)議或通訊子系統(tǒng)無(wú)關(guān)。支持下列命令:   FIONBIO:允許或禁止套接口s的非阻塞模式。argp指向一個(gè)無(wú)符號(hào)長(zhǎng)整型。如允許非阻塞模式則非零,如禁止非阻塞模式則為零。當(dāng)創(chuàng)建一個(gè)套接口時(shí),它就處于阻塞模式(也就是說(shuō)非阻塞模式被禁止)。這與BSD套接口是一致的。WSAAsynSelect()函數(shù)將套接口自動(dòng)設(shè)置為非阻塞模式。如果已對(duì)一個(gè)套接口進(jìn)行了WSAAsynSelect() 操作,則任何用ioctlsocket()來(lái)把套接口重新設(shè)置成阻塞模式的試圖將以WSAEINVAL失敗。為了把套接口重新設(shè)置成阻塞模式,應(yīng)用程序必須首先用WSAAsynSelect()調(diào)用(IEvent參數(shù)置為0)來(lái)禁至WSAAsynSelect()。   FIONREAD:確定套接口s自動(dòng)讀入的數(shù)據(jù)量。argp指向一個(gè)無(wú)符號(hào)長(zhǎng)整型,其中存有ioctlsocket()的返回值。如果s是SOCKET_STREAM類(lèi)型,則FIONREAD返回在一次recv()中所接收的所有數(shù)據(jù)量。這通常與套接口中排隊(duì)的數(shù)據(jù)總量相同。如果S是SOCK_DGRAM 型,則FIONREAD返回套接口上排隊(duì)的第一個(gè)數(shù)據(jù)報(bào)大小。   SIOCATMARK:確實(shí)是否所有的帶外數(shù)據(jù)都已被讀入。這個(gè)命令僅適用于SOCK_STREAM類(lèi)型的套接口,且該套接口已被設(shè)置為可以在線接收帶外數(shù)據(jù)(SO_OOBINLINE)。如無(wú)帶外數(shù)據(jù)等待讀入,則該操作返回TRUE真。否則的話返回FALSE假,下一個(gè)recv()或recvfrom()操作將檢索“標(biāo)記”前一些或所有數(shù)據(jù)。應(yīng)用程序可用SIOCATMARK操作來(lái)確定是否有數(shù)據(jù)剩下。如果在“緊急”(帶外)數(shù)據(jù)前有常規(guī)數(shù)據(jù),則按序接收這些數(shù)據(jù)(請(qǐng)注意,recv()和recvfrom()操作不會(huì)在一次調(diào)用中混淆常規(guī)數(shù)據(jù)與帶外數(shù)據(jù))。argp指向一個(gè)BOOL型數(shù),ioctlsocket()在其中存入返回值。   兼容性:   本函數(shù)為Berkeley套接口函數(shù)ioctl()的一個(gè)子集。其中沒(méi)有與FIOASYNC等價(jià)的命令,SIOCATMARK是套接口層次支持的唯一命令。   返回值:   成功后,ioctlsocket()返回0。否則的話,返回SOCKET_ERROR錯(cuò)誤,應(yīng)用程序可通過(guò)WSAGetLastError()獲取相應(yīng)錯(cuò)誤代碼。   錯(cuò)誤代碼:   WSANOTINITIALISED:在使用此API之前應(yīng)首先成功地調(diào)用WSAStartup()。   WSAENETDOWN:WINDOWS套接口實(shí)現(xiàn)檢測(cè)到網(wǎng)絡(luò)子系統(tǒng)失效。   WSAEINVAL:cmd為非法命令,或者argp所指參數(shù)不適用于該cmd命令,或者該命令   不適用于此種類(lèi)型的套接口。   WSAEINPROGRESS:一個(gè)阻塞的WINDOWS套接口調(diào)用正在運(yùn)行中。   WSAENOTSOCK:描述字不是一個(gè)套接口。   參見(jiàn):   socket(), setsockopt(), getsockopt(), WSAAsyncSelect().   該命令     不適用于此種類(lèi)型的套接口。     WSAEINPROGRESS:一個(gè)阻塞的WINDOWS套接口調(diào)用正在運(yùn)行中。     WSAENOTSOCK:描述字不是一個(gè)套接口。

            posted @ 2010-11-04 12:13 鄭興鋒 閱讀(548) | 評(píng)論 (0)編輯 收藏

            2010年10月21日

             
            通信模塊圖

              
              通信關(guān)系圖
             
            其中有不足的地方, 希望朋友們提出意見(jiàn).

            posted @ 2010-10-21 17:51 鄭興鋒 閱讀(282) | 評(píng)論 (0)編輯 收藏

            僅列出標(biāo)題  下一頁(yè)
            久久AAAA片一区二区| 久久这里只有精品首页| 欧美伊香蕉久久综合类网站| 久久久WWW成人免费精品| 亚洲国产成人久久综合一区77| 一本色道久久HEZYO无码| 一本伊大人香蕉久久网手机| 一本久久a久久精品综合香蕉| 丁香狠狠色婷婷久久综合| 欧洲性大片xxxxx久久久| 久久A级毛片免费观看| 午夜视频久久久久一区| 伊人色综合久久| 久久综合精品国产二区无码| 久久人人爽人人爽人人片AV麻豆| 色婷婷久久综合中文久久蜜桃av| 久久青青草原亚洲av无码| 久久精品国产亚洲av日韩| 狠狠色丁香婷婷久久综合五月| 色成年激情久久综合| 久久亚洲私人国产精品vA| 亚洲欧美日韩精品久久亚洲区| 91久久婷婷国产综合精品青草 | 亚洲精品无码久久久久久| 精品国产青草久久久久福利| 国产成人久久激情91| 久久综合亚洲欧美成人| 久久WWW免费人成一看片| 久久性生大片免费观看性| 青青草原综合久久| 97久久天天综合色天天综合色hd| 日产精品久久久久久久性色| 午夜精品久久久久久毛片| 久久久久久久女国产乱让韩| 狠狠色丁香久久婷婷综合_中| 伊色综合久久之综合久久| 欧美午夜精品久久久久久浪潮| 久久亚洲AV永久无码精品| 日本欧美国产精品第一页久久| 久久精品女人天堂AV麻| 久久伊人五月天论坛|