VS2008Sp1+SilverLight3+Blend3
首先安裝Visual Studio 2008 專業(yè)版(只要空間夠,與VS2005共存完全沒有問題),打上 Microsoft Visual Studio 2008 Service Pack 1。安裝Sp1的時(shí)候可能花的時(shí)間有點(diǎn)久,>=安裝VS2008的時(shí)間,考驗(yàn)?zāi)托牡臅r(shí)間到了。。
要注意的是電腦里有的是VS2008 Beta ,那就麻煩 了,升級到VS2008正式版比想象中的困難,實(shí)在不行就只能用第2種組合了。
下面就開始配置SilverLight了,首先安裝
Microsoft® Silverlight™ 3 Tools for Visual Studio 2008 SP1
,注意語言選擇要與VS2008的對應(yīng)。
接著是Silverlight 3 Toolkit July 2009,Xaml的界面設(shè)計(jì)Microsoft Expression Blend 3 Preview目前只有英文版,所有的都用最新的嘗嘗鮮。。
VS2010Beta 1+SilverLight2+SilverLight3
vs2010Beta1是基于WPF的,因此界面與很多新特性比以前看起來是舒服多了,不過性能方面那就嚴(yán)重地有待提高,無響應(yīng)的幾率相對于
VS2008至少增加了20%。安裝過程中會重啟(Framework
4),鏡像只有1288M,但安裝系統(tǒng)盤的大小基本要求還是很高的,曾經(jīng)試過最小也要2.4G。
SilverLight2自帶就已經(jīng)安裝了,但現(xiàn)在還不能創(chuàng)建SL2的項(xiàng)目并且F5調(diào)試的時(shí)候也會報(bào)Debug manage,這時(shí)就要安裝依次下面的的就可以O(shè)K了
Microsoft® Silverlight™ 2 軟件開發(fā)工具包
Microsoft® Silverlight™ 3 SDK,
Silverlight.3.0_Developer
。在裝Silverlight.3.0_Developer安裝的過程中可能會提示已經(jīng)安裝更新版本,老老實(shí)實(shí)去卸載吧Silverlight3吧,不然調(diào)試功能就沒有機(jī)會享用 了。。
至此為止,以上兩種組合的SilverLight開發(fā)環(huán)境已經(jīng)完成了,希望對大家有幫助。下次將發(fā)布“使用Silverlight技術(shù),Bing搜索API和遠(yuǎn)端WCF/WPF實(shí)現(xiàn)Ink手寫搜索框”開發(fā)過程與源碼。
posted @
2009-10-22 12:25 暗夜教父 閱讀(304) |
評論 (0) |
編輯 收藏
apt-get 使用指南
原文出處:https://help.ubuntu.com/community/AptGetHowto
原文作者:UbuntuWiki
授權(quán)許可:
- 創(chuàng)作共享協(xié)議Attribution-ShareAlike 2.0
- GNU自由文檔許可證
翻譯人員:sigus 5451vs5451 youyou keke initnas
校正人員:MillenniumDark
適用版本:
文章狀態(tài):等待校正
apt-get使用source.list文件進(jìn)行軟件包管理。如果您想了解關(guān)于如何編輯和更新source.list中的條目的信息,請參閱SourcesList
“起初GNU/Linux系
統(tǒng)中只有.tar.gz。用戶必須自己編譯他們想使用的每一個(gè)程序。在Debian出現(xiàn)之後,人們認(rèn)為有必要在系統(tǒng)中添加一種機(jī)制用來管理安裝在計(jì)算機(jī)上
的軟件包。人們將這套系統(tǒng)稱為dpkg。至此著名的‘package’首次在GNU/Linux上出現(xiàn)。不久之後紅帽子也開始著手建立自己的包管理系統(tǒng)
‘rpm’。
“GNU/Linux的創(chuàng)造
者們很快又陷入了新的窘境。他們希望通過一種快捷、實(shí)用而且高效的方式來安裝軟件包。這些軟件包可以自動處理相互之間的依賴關(guān)系,并且在升級過程中維護(hù)他
們的配置文件。Debian又一次充當(dāng)了開路先鋒的角色。她首創(chuàng)了APT(Advanced Packaging Tool)。這一工具後來被Conectiva
移植到紅帽子系統(tǒng)中用于對rpm包的管理。在其他一些發(fā)行版中我們也能看到她的身影。”
"同時(shí),apt是一個(gè)很完整和先進(jìn)的軟件包管理程序,使用它可以讓你,又簡單,又準(zhǔn)確的找到你要的的軟件包, 并且安裝或卸載都很簡潔。 它還可以讓你的所有軟件都更新到最新狀態(tài),而且也可以用來對ubuntu進(jìn)行升級。"
"apt是需要用命令來操作的軟件,不過現(xiàn)在也出現(xiàn)了很多有圖形的軟件,比如Synaptic, Kynaptic 和 Adept。"
下面將要介紹的所有命令都需要sudo!使用時(shí)請將“packagename”和“string”替換成您想要安裝或者查找的程序。
* apt-get autoclean——定期運(yùn)行這個(gè)命令來清除那些已經(jīng)卸載的軟件包的.deb文件。通過這種方式,您可以釋放大量的磁盤空間。如果您的需求十分迫切,可以使用apt-get clean以釋放更多空間。這個(gè)命令會將已安裝軟件包裹的.deb文件一并刪除。大多數(shù)情況下您不會再用到這些.debs文件,因此如果您為磁盤空間不足而感到焦頭爛額,這個(gè)辦法也許值得一試。
我是個(gè)賽車發(fā)燒友,想裝個(gè)賽車類游戲玩玩。有哪些賽車類游戲可供選擇呢?
apt-cache search racing game
出來了一大堆結(jié)果。看看有沒有更多關(guān)于torcs這個(gè)游戲的信息。
apt-cache show torcs
看上去不錯(cuò)。這個(gè)游戲是不是已經(jīng)安裝了?最新版本是多少?它屬于哪一類軟件,universe還是main?
apt-cache policy torcs
好吧,現(xiàn)在我要來安裝它!
apt-get install torcs
在
控制臺下我應(yīng)該調(diào)用什么命令來運(yùn)行這個(gè)游戲呢?在這個(gè)例子中,直接用torcs就行了,但并不是每次都這么簡單。我們可一通過查找哪些文件被安裝到了
“/usr/bin”文件夾下來確定二進(jìn)制文件名。對于游戲軟件,這些二進(jìn)制文件將被安裝到“/usr/games”下面。對于系統(tǒng)管理工具相應(yīng)的文件夾
是“/usr/sbin”。
dpkg -L torcs|grep /usr/games/
這個(gè)命令的前面一部分顯示軟件包“torcs”安裝的所有文件(您自己試試看)。通過命令的第二部分,我們告訴系統(tǒng)只顯示前一部分的輸出結(jié)果中含有“/usr/games”的那些行。
這個(gè)游戲很酷哦。說不定還有其他賽道可玩的?
apt-cache search torcs
我的磁盤空間不夠用了。我得把a(bǔ)pt的緩存空間清空才行。
apt-get clean
哦不,老媽叫我把機(jī)器上的所有游戲都刪掉。但是我想把配置文件保留下來,這樣待會我只要重裝一下就可以繼續(xù)玩了。
apt-get remove torcs
如果我想連配置文件一塊刪除:
apt-get remove --purge torcs
deborphan和debfoster工具可以找出已經(jīng)安裝在系統(tǒng)上的不會被用到的軟件包。
您可以通過定義別名(alias)來提高這些命令的輸入速度。例如,您可以在您的*~/.bashrc*文件中添加下列內(nèi)容
alias acs='apt-cache search'
alias agu='sudo apt-get update'
alias agg='sudo apt-get upgrade'
alias agd='sudo apt-get dist-upgrade'
alias agi='sudo apt-get install'
alias agr='sudo apt-get remove'
或者使用前面介紹的aptitude命令,如“alias agi='sudo aptitude install'”。
可以通過三種方法為apt-get設(shè)置http代理
方法一
這是一種臨時(shí)的手段,如果您僅僅是暫時(shí)需要通過http代理使用apt-get,您可以使用這種方式。
在使用apt-get之前,在終端中輸入以下命令(根據(jù)您的實(shí)際情況替換yourproxyaddress和proxyport)。
export http_proxy=http://yourproxyaddress:proxyport
方法二
這種方法要用到/etc/apt/文件夾下的apt.conf文件。如果您希望apt-get(而不是其他應(yīng)用程序)一直使用http代理,您可以使用這種方式。
注意: 某些情況下,系統(tǒng)安裝過程中沒有建立apt配置文件。下面的操作將視情況修改現(xiàn)有的配置文件或者新建配置文件。
sudo gedit /etc/apt/apt.conf
在您的apt.conf文件中加入下面這行(根據(jù)你的實(shí)際情況替換yourproxyaddress和proxyport)。
Acquire::http::Proxy "http://yourproxyaddress:proxyport";
保存apt.conf文件。
方法三
這種方法會在您的主目錄下的.bashrc文件中添加兩行。如果您希望apt-get和其他應(yīng)用程序如wget等都使用http代理,您可以使用這種方式。
gedit ~/.bashrc
在您的.bashrc文件末尾添加如下內(nèi)容(根據(jù)你的實(shí)際情況替換yourproxyaddress和proxyport)。
http_proxy=http://yourproxyaddress:proxyport
export http_proxy
保存文件。關(guān)閉當(dāng)前終端,然後打開另一個(gè)終端。
使用apt-get update或者任何您想用的網(wǎng)絡(luò)工具測試代理。我使用firestarter查看活動的網(wǎng)絡(luò)連接。
如果您為了糾正錯(cuò)誤而再次修改了配置文件,記得關(guān)閉終端并重新打開,否自新的設(shè)置不會生效。
posted @
2009-10-19 10:59 暗夜教父 閱讀(382) |
評論 (0) |
編輯 收藏
如果想封掉國內(nèi)ip或者封掉國外ip,總歸要現(xiàn)有國內(nèi)的ip段才可以。如果要做dns智能解析,也要有各地各運(yùn)營商的ip段才行。網(wǎng)上有很多各式各樣的ip表,但很多都過期了,也不全。如果要做一個(gè)比較完整的ip數(shù)據(jù),還是要靠APNIC才行。
亞太互聯(lián)網(wǎng)絡(luò)信息中心(Asia-Pacific Network InformationCenter,簡稱APNIC)坐落于澳大利亞的布里斯班,是全球現(xiàn)有4個(gè)地區(qū)性互聯(lián)網(wǎng)注冊管理機(jī)構(gòu)(RIR)之一,負(fù)責(zé)向亞太地區(qū)64個(gè)經(jīng)濟(jì)體提供IP(v4及v6)地址和自治系統(tǒng)(AS)號碼分配,以及反向DNS授權(quán)服務(wù)的非營利性會員組織。其會員單位包括ISP、國家(或地區(qū))互聯(lián)網(wǎng)注冊管理機(jī)構(gòu)(NIR)等互聯(lián)網(wǎng)組織。
如果要找出國內(nèi)的ip地址段,這個(gè)比較簡單
國家IP段數(shù)據(jù)下載地址:http://ftp.apnic.net/apnic/dbase/data/country-ipv4.lst
下載數(shù)據(jù)后,將國家為cn的ip挑出來自己處理一下就可以。
如果要找出各地各運(yùn)營商的ip段
wget http://ftp.apnic.net/apnic/dbase/tools/ripe-dbase-client-v3.tar.gz
tar xzvf ripe-dbase-client-v3.tar.gz
cd whois-3.1
./configure
make
完成上述編譯安裝工作后,我們開始獲取IP地址段;
中國網(wǎng)通:
./whois3 -h whois.apnic.net -l -i mb MAINT-CNCGROUP > /var/cnc
中國電信:
./whois3 -h whois.apnic.net -l -i mb MAINT-CHINANET > /var/chinanet
中國鐵通:
./whois3 -h whois.apnic.net -l -i mb MAINT-CN-CRTC > /var/crtc
打開獲取后的文件可以看到里面的信息非常詳細(xì),甚至可以看到各個(gè)分公司的負(fù)責(zé)人、電話、電子郵件等等信息。如果想得到一份整齊干凈的IP地址段文件,只要用grep和awk簡單過濾就可以了
然后在apache中設(shè)置一下權(quán)限就可以。
Order deny,allow
Deny from 113.0.0.0/13
……………………………….
Deny from 61.240.0.0/14
posted @
2009-10-17 00:41 暗夜教父 閱讀(339) |
評論 (0) |
編輯 收藏
我用的是lamp集成環(huán)境是xampp,linux下是lampp,其實(shí)都是一個(gè)東西。
想改變一下自己老土的調(diào)試方式,所以試用一下zend debugger和xdebug
言歸正傳,如何讓三者共存呢。(理論上,你用zend debugger就不必再使用xdebug,反之亦然)
xampp已經(jīng)給好了zend optimizer的配置,并且xdebug也已經(jīng)默認(rèn)給配置好了,只是都沒有啟用而已
第一步:啟用zend optimizer
在php.ini中,找到zend_optimizer.enable_loader,把值高為1即可
如:
[Zend]
zend_extension_ts = “D:\xampp\php\zendOptimizer\lib\ZendExtensionManager.dll”
zend_extension_manager.optimizer_ts = “D:\xampp\php\zendOptimizer\lib\Optimizer”
zend_optimizer.enable_loader = 1
zend_optimizer.optimization_level=15
zend_optimizer.license_path =
; Local Variables:
; tab-width: 4
; End:
第二步:加載zend debugger
這里是一個(gè)需要注意的地方
下載zend debugger: 地址:http://downloads.zend.com/pdt/server-debugger/,下載符合你操作系統(tǒng)的版本, 保存到自定義的目錄,例如d:/xampp/php/zenddebugger
在該目錄下建立一個(gè)相應(yīng)當(dāng)前php版本的文件夾, 如當(dāng)前php版本php5.26, 即在該文件夾下建立php-5.2.x文件夾, 注: 此處X為真實(shí)的字符,而不是一個(gè)代表符。
將下載的debugger中相應(yīng)版本的ZendDebugger.dll考到該目錄下。
再配置 php.ini,加入
[Debugger]
zend_extension_manager.debug_server_ts=”D:\xampp\php\zenddebugger”
zend_debugger.allow_hosts=127.0.0.1/32,192.168.0.0/44
zend_debugger.expose_remotely=always
重啟apache,查看phpinfo,如果看到
with Zend Extension Manager v1.2.0, Copyright (c) 2003-2007, by Zend Technologies
with Zend Optimizer v3.3.3, Copyright (c) 1998-2007, by Zend Technologies
with Zend Debugger v5.2.15, Copyright (c) 1999-2008, by Zend Technologies
就說明成功了
第三步:加載xdebug
我們可以以擴(kuò)展形式加載xdebug,就避免了和zend optimizer沖突。
extension=php_xdebug.dll
注意php_xdebug.dll要在xampp/php/ext目錄下
然后php.ini中添加的內(nèi)容 (xampp已經(jīng)添加好,我們只需要去掉注釋即可)
[XDebug]
;; Only Zend OR (!) XDebug
;zend_extension_ts=”D:\xampp\php\ext\php_xdebug.dll”
xdebug.remote_enable=true
xdebug.remote_host=127.0.0.1
xdebug.remote_port=9000
;xdebug.remote_handler=dbgp
;xdebug.profiler_enable=1
;xdebug.profiler_output_dir=”D:\xampp\tmp”
再重啟apache, OK。 開始測試
結(jié)果是,zend debugger可以和zend optimize共存,但xdebug不能和zend optimize共存
如果使用dll方式加載xdebug,會有錯(cuò)誤提示。并且不再執(zhí)行
posted @
2009-10-12 15:43 暗夜教父 閱讀(1273) |
評論 (0) |
編輯 收藏
為啥要PATCH?
Mnesia最大的缺陷是存儲限制。這不是數(shù)據(jù)庫系統(tǒng)的錯(cuò)誤,因?yàn)镸nesia能夠控制虛擬數(shù)據(jù)的大小。主要的問題在于過時(shí)的Erlang DETS存儲引擎,速度慢并且使用的32位偏移量(限制單文件大小為2GB)。
思路?
超乎想象的 mnesia 補(bǔ)丁包 mnesiaex 。這個(gè)東西解除了加在 mnesia 數(shù)據(jù)庫系統(tǒng)上所有的限制(雖說上面已經(jīng)提到,實(shí)際上 mnesia 代碼本身沒有什么真正的限制)——你現(xiàn)在可以用 SleepyCat/BerkeleyDB/MySQL/Amazon S3/Tokyo Cabinet/… 甚至是你自己喜歡的某種東西來當(dāng)作 mnesia 的后端,就像 ets/dets 一樣。而訪問的接口仍保持不變——繼續(xù)沿用 mnesia 的接口,一行也不用改。 DIY 這種擴(kuò)展也變得相當(dāng)容易,寫一個(gè) behavior 就成了。
實(shí)現(xiàn)過程
1:與從源代碼編譯的方式安裝Erlang
tar xvf otp_src_R12B-5.tar.gz
cd otp_src_R12B-5
./configure & make & make install
注意:我的系統(tǒng)是RHEL 5.3,默認(rèn)安裝目錄為/usr/local/erlang
2:安裝Mnesiaex
tar xvf mnesia-4.4.7.6.tar.gz
cd mnesia-4.4.7.6
./configure --prefix=/usr/local
make
make check
make install
注意:這里一定要指定prefix,不然就裝到/usr目錄去了
3:安裝Tokyo Cabinet
tar xvf tokyocabinet-1.4.10.tar.gz
cd tokyocabinet-1.4.10
./configure --prefix=/usr
make & make install
3:安裝tcerl
tar xvf tcerldrv-1.3.1e.tar.gz
cd tcerldrv-1.3.1e
./configure --prefix=/usr
make & make install
tar xvf tcerl-1.3.1e.tar.gz
cd tcerl-1.3.1e
./configure --prefix=/usr/local
make & make install
本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/jimmychou/archive/2009/03/13/3988468.aspx
posted @
2009-09-29 15:12 暗夜教父 閱讀(913) |
評論 (0) |
編輯 收藏
http://shiningray.cn/some-facts-about-erlang-and-smp.html
原文:http://groups.google.com/group/erlang-questions/browse_thread/thread/7827f5e32681ca8e
by.Kenneth Erlang/OTP team, Ericsson
譯:ShiningRay
以下是一些Erlang SMP實(shí)現(xiàn)的細(xì)節(jié)和與性能與伸縮性相關(guān)一些簡單介紹。
幾周之內(nèi)還有有一個(gè)關(guān)于多核如何運(yùn)作以及未來如何發(fā)展的更詳細(xì)的介紹。我打算將一些內(nèi)容放在我的報(bào)告中,將于9月27日的ICFP2008,Erlang Workshop在Victoria BC展示給大家。
沒有SMP支持的Erlang VM只有1個(gè)運(yùn)行在主處理線程中的調(diào)度器。該調(diào)度器從運(yùn)行隊(duì)列(run-queue)中取出可以運(yùn)行的Erlang進(jìn)程以及IO任務(wù),而且因?yàn)橹挥幸粋€(gè)線程訪問他們所以無須鎖定任何數(shù)據(jù)。
而帶有SMP支持的Erlang VM可以有一個(gè)或多個(gè)調(diào)度器,每個(gè)運(yùn)行在一個(gè)線程中。調(diào)度器從同一個(gè)公共運(yùn)行隊(duì)列中取出可運(yùn)行的Erlang進(jìn)程和IO任務(wù)。在SMP VM中所有的共享數(shù)據(jù)結(jié)構(gòu)都會由鎖進(jìn)行保護(hù),運(yùn)行隊(duì)列就是這樣一個(gè)由鎖保護(hù)的數(shù)據(jù)結(jié)構(gòu)。
從OTP R12B開始,如果操作系統(tǒng)報(bào)告有多于1個(gè)的CPU(或者核心)VM的SMP版本會自動啟動,并且根據(jù)CPU或者核心的數(shù)量啟動同樣數(shù)量的調(diào)度器。
你可以從“erl”命令打印出來的第一行看到它選擇了哪些參數(shù)。例如:
Erlang (BEAM) emulator version 5.6.4 [source] [smp:4] [asynch-threads:0] …..
其中“[smp:4]”表示SMP VM運(yùn)行了4個(gè)調(diào)度器。
默認(rèn)值可以用“-smp [enable|disable|auto]”來替換,auto是默認(rèn)的。如果smp被啟用了(-smp enable),要設(shè)置調(diào)度器的數(shù)量可以使用“+S Number”其中Number是調(diào)度器的數(shù)量(1到1024)
注意1:運(yùn)行多于CPU或核心總數(shù)的調(diào)度器不會有任何提升。
注意2:在某些操作系統(tǒng)中一個(gè)進(jìn)程可使用的CPU或者核心的數(shù)量可以被限制。例如,在Linux中,命令“taskset”就可以實(shí)現(xiàn)這個(gè)功能。 Erlang VM目前還只能探測CPU或者核心的總數(shù),不會考慮“taskset”所設(shè)置的掩碼。正因如此,例如可能會出現(xiàn)(已經(jīng)出現(xiàn)過了)即使Erlang VM運(yùn)行了4個(gè)調(diào)度器,也只使用了2個(gè)核心。OS會進(jìn)行限制因?yàn)樗紤]“taskset”所設(shè)置的掩碼。
每個(gè)Erlang VM的調(diào)度器都運(yùn)行于一個(gè)OS線程上,是OS來決定線程是否執(zhí)行在不同的核心上。一般來說OS會很好地處理這個(gè)問題并且會保證線程在執(zhí)行期間運(yùn)行于同一個(gè)核心上。
Erlang進(jìn)程會被不同的調(diào)度器運(yùn)行,因?yàn)樗麄兪菑囊粋€(gè)公共運(yùn)行隊(duì)列中被取出,由首先可用的調(diào)度器運(yùn)行。
性能和伸縮性
只有一個(gè)調(diào)度器的SMP VM要比非SMP的VM稍微慢那么一點(diǎn)點(diǎn)。SMP VM內(nèi)部需要用到各種鎖,不過只要不存在鎖的爭用,那么由鎖引起的開銷不會非常大(就是鎖爭用上面需要花時(shí)間)。這也解釋了為何在某些情況下,運(yùn)行多個(gè)只有一個(gè)調(diào)度器的SMP VM要比包含多個(gè)調(diào)度器的單一SMP VM更加高效。當(dāng)然運(yùn)行多個(gè)VM要求應(yīng)用可以按照多個(gè)并行任務(wù)的方式運(yùn)行并且之間沒有或者幾乎不通訊。
一個(gè)程序是否能在多核上的SMP VM中良好地進(jìn)行提升很大程度上取決于程序的性質(zhì),某些程序可以保持線性提升至8核甚至16核,同時(shí)其他某些程序基本不能提升,連2核都不行。實(shí)際應(yīng)用中很多程序都能在主流市場的核心數(shù)上得到提升,見下文。
若并行的持續(xù)“通話”由每個(gè)核心一個(gè)或多個(gè)Erlang進(jìn)程來表示,實(shí)際的支持大量通話的電信產(chǎn)品已經(jīng)先現(xiàn)出在雙核和四核處理器上不俗的伸縮性。注意,這些產(chǎn)品是在SMP VM和多核處理器出現(xiàn)很久以前按照普通的Erlang風(fēng)格來寫的,他們也能無須任何修改甚至不需重新編譯代碼就能從Erlang SMP VM中獲益。
SMP性能得到持續(xù)改進(jìn)
SMP實(shí)現(xiàn)正被不斷改進(jìn)以便能得到更好的性能和伸縮性。在每個(gè)服務(wù)發(fā)布版R12B-1,2,3,4,5…,R13B等等中,你都能發(fā)現(xiàn)新的優(yōu)化。
一些已知的瓶頸
單一的常見運(yùn)行隊(duì)列隨著CPU或核心的數(shù)量的增加會成為一個(gè)顯著的瓶頸。
這從4核開始往上就會顯現(xiàn)出來,不過4核仍然可以為多數(shù)應(yīng)用程序提供不錯(cuò)的性能。我們正在從事一個(gè)每個(gè)調(diào)度器一個(gè)運(yùn)行隊(duì)列的解決方法作為目前最重要的改進(jìn)。
Ets表格會引入鎖。在R12B-4之前在每次對一個(gè)ets-table的訪問中會用到兩個(gè)鎖,但是在R12B-4中meta-table的鎖被優(yōu)化過,可以顯著減少爭用(前面已經(jīng)提到爭用是有很大代價(jià)的)。如果很多Erlang進(jìn)程訪問同一個(gè)表格,就會有很多鎖爭用造成性能降低尤其當(dāng)這些進(jìn)程主要工作是訪問ets-table。鎖存在于表級而非記錄級。注意!這也會影響到Mnesia因?yàn)镸nesia用到了很多ets-table。
我們關(guān)于SMP的策略
當(dāng)我們開始實(shí)現(xiàn)SMP VM的最初,我們就確定了策略:“首先讓它可以運(yùn)行,然后測量,然后優(yōu)化”。自從2006年五月我們發(fā)布了第一個(gè)穩(wěn)定的SMP VM(R11B)以來,我們一直遵循著這個(gè)策略。
還有更多已知的東西可以改進(jìn),我們會按照性能的收益大小先后各個(gè)擊破。
我們將主要的精力放在多核(大于4)上更好的連續(xù)伸縮性上。
卓越典范
即使SMP系統(tǒng)有還有一些已知的瓶頸不過已經(jīng)有不錯(cuò)的整體性能和伸縮性,同時(shí)我相信在讓程序員利用多核機(jī)器事半功倍方面,我們是一個(gè)卓越的典范。
posted @
2009-09-24 22:23 暗夜教父 閱讀(603) |
評論 (0) |
編輯 收藏
以下是在
erlang項(xiàng)目開發(fā)中的一些記錄,即包含很多通俗易懂的原則,也包含一些似是而非的建議,比較混亂,還沒有積累到一個(gè)可以分門別類的地步,各位就將就看吧..
:)
* 確保沒有任何編譯警告
*
Erlang中String采用list實(shí)現(xiàn),32位系統(tǒng)中,其1個(gè)字符用8個(gè)字節(jié)的空間(4個(gè)保存value,
4個(gè)保存指針)。因此string速度較慢,空間占用較大
* 在Server中,總是盡力書寫尾遞歸(tail-recursive)的函數(shù)
* 使用'++'時(shí),left list會被拷貝,然后添加到right list的頭部,因此最好把length較短的list放在左側(cè)
* 避免使用regexp,如果需要正則表達(dá)式,請使用re
*
timer模塊的大部分函數(shù)實(shí)現(xiàn),依賴于一個(gè)process,如果過多使用timer,會導(dǎo)致這個(gè)process負(fù)載過大,影響效率。
推薦使用
erlang:send_after/3及
erlang:start_timer/3
* 避免使用list_to_atom/1,因?yàn)?span id="kgakems" class="hilite1">erlang中atom數(shù)量最大為1048576, 且不進(jìn)行GC控制。因此如果持續(xù)性的調(diào)用list_to_atom/1
可能很容易達(dá)到系統(tǒng)上限,從而導(dǎo)致emulator terminate。請使用list_to_existing_atom/1。
*
list內(nèi)部實(shí)現(xiàn)為一個(gè)列表,因此length(List), 需要遍歷整個(gè)list比較耗時(shí)
*
對于不同的數(shù)據(jù)類型,使用不同的size函數(shù):tuple_size/1, byte_size/1, bit_size/1
* 使用binary
match來進(jìn)行binary的分割,而不使用split_binary/2
*
如果兩個(gè)list都擁有很多數(shù)據(jù),那么請不要使用'--',而是將數(shù)據(jù)轉(zhuǎn)化到ordsets,然后調(diào)用ordsets:substract/2.
*
對于binary相關(guān)操作可以進(jìn)行binary優(yōu)化(bin_opt_info編譯選項(xiàng))代碼框架:
*
f(<<Pattern1,...,Rest/bits>>,...) ->
... % Rest is
not used here
f(Rest,...);
f(<<Pattern2,...,Rest/bits>>,...) ->
... % Rest is not
used here
f(Rest,...);
...
f(<<>>, ...)
->
ReturnValue.
*
調(diào)用lists:flatten/1可以將list扁平化,這個(gè)操作代價(jià)很大,比'++'還要昂貴。下面這些時(shí)候我們可以避免:
將數(shù)據(jù)發(fā)送給port時(shí)
調(diào)用list_bo_binary/1和iolist_to_binary前
* 小的函數(shù)可以讓您方便的找出錯(cuò)誤的函數(shù)和代碼
* 不要在同一行出現(xiàn)相同的符號
20 some_fun() ->
21 L = [{key1, v1},
{key2, [some_record#v21, v22]}],
22 ...
編譯時(shí),會提示line 21 '[' 語法錯(cuò)誤,
因?yàn)?1行有多個(gè) '[' ,所以這個(gè)bug不能準(zhǔn)確定位,你需要花時(shí)間去排查代碼。
好的做法是:
20 some_fun() ->
21 L = [{key1, v1},
22 {key2, [some_record#v21, v22]}
23 ],
...
這樣,編譯其會提示你 line 22 '['
語法錯(cuò)誤,你很開就知道是那個(gè)地方錯(cuò)了。
* 使用 CTRL + \ 或 init:stop(), 可以退出
Erlang, 使用CTRL + G 及 CTRL + C 彈出菜單選項(xiàng),可以選擇是否退出
Erlang。
其中CTRL + G可以用來連接其他的shell, CTRL + C可以查看其他一些系統(tǒng)信息
Ctrl + C abort 是野蠻的退出方式
* use "open_port({fd,0,2}, [out])" make
erlang program write standard error to unix system
* If you don't run experiments before you start designing a new system,
your entire system will be an experiment!
* standard data structure
desc:
Module Description
sets sets, i.e. a collection of unique
elements.
gb_sets sets, but based on a general balanced data structure
gb_tree a general balanced tree
dict maps, also called associative
arrays
ets hash tables and ordered sets (trees)
dets on-disk hash tables
Suggestion:
elments count: 0 - 100 | 100 - 10000 | 10000 -
our
select : list | ets | gb_tree
* 通過code:clash/0
檢測代碼中是否有module沖突現(xiàn)象(sticky)
* epmd -d -d 啟動 epmd 可以查看
erlang node之間的通訊
*
將正常的邏輯代碼和錯(cuò)誤處理代碼分離,發(fā)生錯(cuò)誤時(shí),盡管錯(cuò)誤。由另一個(gè)錯(cuò)誤處理模塊進(jìn)行處理
* 類似于操作系統(tǒng),我們的程序也可以分為kernel 和
user 兩層, 對于kernel絕對不能出現(xiàn)錯(cuò)誤, 對于user可以出現(xiàn)錯(cuò)誤,進(jìn)行恢復(fù)
*
process頂層loop涉及的代碼及函數(shù),最好在一個(gè)module中實(shí)現(xiàn)
* process 的register
name和module名稱一致, 便于尋找代碼
* 每個(gè)process具有一個(gè)單一的角色,比如:supervisor 用來進(jìn)行錯(cuò)誤恢復(fù),
work 工作者,可以出現(xiàn)錯(cuò)誤, trusted worker 不會出現(xiàn)錯(cuò)誤
*
通過函數(shù)調(diào)用可以實(shí)現(xiàn)的功能,就不要使用sever實(shí)現(xiàn)(如gen_server, 及類似的loop 實(shí)現(xiàn))
*
給消息加一個(gè)tag,在發(fā)生錯(cuò)誤的時(shí)候,可以定位到消息,同時(shí)也有利于程序的穩(wěn)健
*
在消息循環(huán)中,對于unknown的消息,請調(diào)用lib:flush_receive/0 將其清除,減輕process msg queue的長度
*
server中總是書寫尾遞歸的循環(huán)
* 盡量使用record, 而不是原始的tuple來表現(xiàn)數(shù)據(jù)結(jié)構(gòu), 在使用record時(shí),使用select
match:
#person{name = Name, age = Age} = Person
*
對于返回值,最好也添加一個(gè)tag,用來說明返回值類型,或者執(zhí)行成功與否
* 盡可能少的使用catch和try,在
erlang程序中,不推薦主動捕獲異常。只有當(dāng)我們的邏輯特別復(fù)雜,我們可以使用throw來返回?cái)?shù)據(jù),使用catch來獲取返回值。
* 當(dāng)然程序與外界交互,外界數(shù)據(jù)不可靠時(shí),需要使用catch和try
* 慎重使用process dictory,
當(dāng)你使用get/1, put/1時(shí),你的應(yīng)用會具有很大的slide effect。可以通過加入一個(gè)新的參數(shù)來保存原本需要存儲到process
dictory中數(shù)據(jù)
* 如果不想使自己糊涂,請不要使用import
*
使用export時(shí),將功能類似的接口組合在一起,并添加合理的注視,這樣你的接口更清晰,別人使用起來更方便
* 不要書寫嵌套太深的代碼
* 不要書寫太長的module
* 不要書寫太長的函數(shù)
* 每行代碼不能太長
* 避免使用
"_" 匿名變量,請為每個(gè)變量選擇有意義的名稱,如夠某個(gè)變量暫時(shí)不使用,請以下劃線 "_" 開始
* {error,
enfile}
enfile error in socket
是以為內(nèi)linux系統(tǒng)中 ulimit 限制, 在root下修改:ulimit -n 25000
* {error, enotconn}
表示socket已經(jīng)關(guān)閉
* 在
erlang開發(fā)時(shí),慎重使用macro,因?yàn)?span id="mwaseec" class="hilite1">erlang的single
assign的緣故,同時(shí)調(diào)用某個(gè)marco,而macro又定義了某個(gè)變量,可能導(dǎo)致badmatch錯(cuò)誤。
比如:
-define(ADDLINEINFO1(F),
(
begin
Str1 =
lists:concat(["[Mod:", ?MODULE, " Line:", ?LINE, "]"]),
Str1 ++ F
end
)).
-define(WARN(Log, F, D), log4erl:warn(Log,
?ADDLINEINFO(F), D)).
如果連續(xù)使用 WARN, 會出現(xiàn)此錯(cuò)誤
*
erlang中可以定義很多環(huán)境變量:
ERL_MAX_ETS_TABLES 設(shè)置最大的ets數(shù)目 默認(rèn)1400
ERL_MAX_PORTS
erlang最大的port數(shù)目 默認(rèn)1024
*
.app文件中的start_phases, 選項(xiàng)既可以用來作為include
applications之間的同步啟動,也可以用來對單個(gè)application進(jìn)行分布啟動。
順序如下
包含included app:
application:start(prim_app)
=> prim_app_cb:start(normal, [])
=> prim_app_cb:start_phase(init, normal, [])
=>
prim_app_cb:start_phase(go, normal, [])
=> incl_app_cb:start_phase(go,
normal, [])
ok
無included app:
application:start(prim_app)
=> prim_app_cb:start(normal, [])
=> prim_app_cb:start_phase(init,
normal, [])
=> prim_app_cb:start_phase(go, normal, [])
ok
*
任何時(shí)候,都要重視函數(shù)的返回值,通過match確保您的預(yù)期,如果發(fā)生錯(cuò)誤,那么就大膽的表達(dá)出來。
posted @
2009-09-24 01:00 暗夜教父 閱讀(616) |
評論 (0) |
編輯 收藏
A Million-user Comet Application with Mochiweb, Part 1
在MacOSX平臺上遇到的一些問題:
一. IPv6導(dǎo)致的問題
在MacOS下測試時(shí)報(bào)錯(cuò)econnrefused,mochi-urls.txt文件的url不能用localhost,得用127.0.0.1才行
在Erlang的郵件列表中找到了解釋:
We have seen the same issue with CouchDB. What
we found out
is that in our case localhost was not only resolving to
127.0.0.1 (IPv4)
but also ::1 (IPv6) and that http:request() would try to
connect to
::1 where no service was listening.
Erlang的http模塊缺省是打開IPv6模式的,當(dāng)測試程序通過http模塊連接localhost時(shí),連接的地址是IPv6的::1地址,但是mochi沒有在此監(jiān)聽,所以連接出錯(cuò)
{error,econnrefused}
解決方法兩種:
1. 將mochi-urls.txt中的地址都改成127.0.0.1
2.
在http:request(…)運(yùn)行之前調(diào)用http:set_options([{ipv6,disabled}]),關(guān)閉測試程序的IPv6模式,使用IPv4模式
理論上還有一種方法:讓mochi服務(wù)器開啟IPv6模式監(jiān)聽,這個(gè)我不知道這么開,
參考
You should teach
Yaws to listen also on IPv6 - “localhost” resolves not
only to IPv4
127.0.0.1, but also to IPv6 ::1.
二. 進(jìn)程能打開的文件描述符數(shù)量的限制
MacOSX下缺省能同時(shí)打開的文件描述符最大數(shù)是256個(gè),使用 ulimit -a命令查看
$ ulimit -a
core file
size (blocks, -c) 0
data seg size (kbytes, -d) 6144
file size (blocks, -f) unlimited
max locked memory
(kbytes, -l) unlimited
max memory size (kbytes, -m) unlimited
open files (-n) 256
pipe
size (512 bytes, -p) 1
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user
processes (-u) 266
virtual memory (kbytes, -v)
unlimited
使用ulimit -n XXXX設(shè)置,但最大數(shù)量還是不能超過10240
查看內(nèi)核每進(jìn)程最大文件數(shù):
$
sysctl kern.maxfiles kern.maxfilesperproc
kern.maxfiles: 12288
kern.maxfilesperproc: 10240
增大每進(jìn)程最大文件數(shù):
$ sudo sysctl -w
kern.maxfilesperproc=20480 kern.maxfiles=22528
然后設(shè)置
$ ulimit -n
20480
注意ulimit只在每個(gè)shell窗口生命周期內(nèi)有效,當(dāng)新開一個(gè)shell后,得再次設(shè)置
sysctl做的修改沒有這個(gè)問題
三、調(diào)節(jié)IP端口號范圍,不然最多只能有15K個(gè)連接
缺省動態(tài)端口號從49152開始,改成2000后最多可以有63K個(gè)連接
sysctl -w net.inet.ip.portrange.hifirst=2000
net.inet.ip.portrange.first=2000
posted @
2009-09-24 00:59 暗夜教父 閱讀(427) |
評論 (0) |
編輯 收藏
本文作者:sodme
本文出處:
http://blog.csdn.net/sodme聲明:本文可以不經(jīng)作者同意任意轉(zhuǎn)載,但任何對本文的引用都須注明作者、出處及此聲明信息。謝謝!!
在網(wǎng)絡(luò)應(yīng)用中,“負(fù)載均衡”已經(jīng)不能算是什么新鮮話題了,從硬件到軟件,也都有了很多的方法來實(shí)現(xiàn)負(fù)載均衡。我們這里討論的負(fù)載均衡,并不是指依靠DNS轉(zhuǎn)向或其它硬件設(shè)備等所作的負(fù)載均衡,而是指在應(yīng)用層所作的負(fù)載均衡。
一般而言,只有在大型在線系統(tǒng)當(dāng)中才有必要引入負(fù)載均衡,那么,多大的系統(tǒng)才能被稱為大型系統(tǒng)呢?比如動輒同時(shí)在線數(shù)十萬的網(wǎng)絡(luò)游戲,比如同時(shí)在線數(shù)在10萬以上的WEB應(yīng)用,這些我們都可以理解為大型系統(tǒng),這本身就是一個(gè)寬泛的概念。
設(shè)計(jì)再好的服務(wù)器程序,其單個(gè)程序所能承載的同時(shí)訪問量也是有限的,面對一個(gè)龐大且日益增長的網(wǎng)絡(luò)用戶群,如何讓我們的架構(gòu)能適應(yīng)未來海量用戶訪問,這
自然就牽涉到了負(fù)載均衡問題。支持百萬級以上的大型在線系統(tǒng),它的架構(gòu)核心就是如何將“百萬”這么大的一個(gè)同時(shí)在線量分?jǐn)偟矫總€(gè)單獨(dú)的服務(wù)器程序上去。真
正的邏輯處理應(yīng)該是在這最終的底層的服務(wù)器程序(如QQ游戲平臺的游戲房間服務(wù)器)上的,而在此之前所存在的那些服務(wù)器,都可以被稱為“引路者”,它們的
作用就是將客戶端一步步引導(dǎo)到這最終的負(fù)責(zé)真正邏輯的底層服務(wù)器上去,我們計(jì)算“百萬級在線”所需要的服務(wù)器數(shù)量,也是首先考慮這底層的邏輯服務(wù)器單個(gè)可
承載的客戶端連接量。
比如:按上篇我們所分析QQ游戲架構(gòu)而言,假設(shè)每個(gè)服務(wù)器程序最高支持2W的用戶在線(假設(shè)一臺機(jī)子只運(yùn)行一個(gè)
服務(wù)器程序),那么實(shí)現(xiàn)150萬的在線量至少需要多少臺服務(wù)器呢?如果算得簡單一點(diǎn)的話,就應(yīng)該是:150/2=75臺。當(dāng)然,這樣算起來,可能并不能代
表真正的服務(wù)器數(shù)量,因?yàn)槌诉@底層的服務(wù)器外,還要包括登錄/賬號服務(wù)器以及大廳服務(wù)器。但是,由于登錄/賬號服務(wù)器和大廳服務(wù)器,它們與客戶端的連接
都屬于短連接(即:取得所需要信息后,客戶端與服務(wù)器即斷開連接),所以,客戶端給這兩類服務(wù)器帶來的壓力相比于長連接(即:客戶端與服務(wù)器始終保持連
接)而言就要輕得多,它們的壓力主要在處理瞬間的并發(fā)訪問上。
“短連接”,是實(shí)現(xiàn)應(yīng)用層負(fù)載均衡的基本手段!!!如果客戶端要始終與登錄/賬號服務(wù)器以及大廳服務(wù)器保持連接,那么這樣作的分層架構(gòu)將是無意義的,這也沒有辦法從根本上解決用戶量不斷增長與服務(wù)器數(shù)量有限之間的矛盾。
當(dāng)然,短連接之所以可以被使用并能維護(hù)正常的游戲邏輯,是因?yàn)樵谕婕铱床坏降牡胤剑?wù)器與服務(wù)器之間進(jìn)行了大量的數(shù)據(jù)同步操作。如果一個(gè)玩家沒有登錄
到登錄服務(wù)器上去而是直接連接進(jìn)了游戲房間服務(wù)器并試圖進(jìn)行游戲,那么,由于游戲房間服務(wù)器與大廳服務(wù)器和登錄/賬號服務(wù)器之間都會有針對于玩家登錄的邏
輯維護(hù),游戲房間服務(wù)器會檢測出來該玩家之前并沒有到登錄服務(wù)器進(jìn)行必要的賬號驗(yàn)證工作,它便會將玩家踢下線。由此看來,各服務(wù)器之間的數(shù)據(jù)同步,又是實(shí)
現(xiàn)負(fù)載均衡的又一必要條件了。
服務(wù)器之間的數(shù)據(jù)同步問題,依據(jù)應(yīng)用的不同,也會呈現(xiàn)不同的實(shí)現(xiàn)方案。比如,我們在處理玩家登錄這個(gè)問
題上。我們首先可以向玩家開放一些默認(rèn)的登錄服務(wù)器(服務(wù)器的IP及PORT信息),當(dāng)玩家連接到當(dāng)前的登錄服務(wù)器后,由該服務(wù)器首先判斷自己同時(shí)連接的
玩家是不是超過了自定義的上限,如果是,由向與該服務(wù)器連接著的“登錄服務(wù)器管理者”(一般是一個(gè)內(nèi)部的服務(wù)器,不直接向玩家開放)申請仲裁,由“登錄服
務(wù)器管理者”根據(jù)當(dāng)前各登錄服務(wù)器的負(fù)載情況選擇一個(gè)新的服務(wù)器IP和PORT信息傳給客戶端,客戶端收到這個(gè)IP和PORT信息之后重定向連接到這個(gè)新
的登錄服務(wù)器上去,完成后續(xù)的登錄驗(yàn)證過程。
這種方案的一個(gè)特點(diǎn)是,在面向玩家的一側(cè),會提供一個(gè)外部訪問接口,而在服務(wù)器集群的內(nèi)部,會提供一個(gè)“服務(wù)器管理者”及時(shí)記錄各登錄服務(wù)器的負(fù)載情況以便客戶端需要重定向時(shí)根據(jù)策略選擇一個(gè)新的登錄接口給客戶端。
采用分布式結(jié)構(gòu)的好處是可以有效分?jǐn)傉麄€(gè)系統(tǒng)的壓力,但是,不足點(diǎn)就是對于全局信息的索引將會變得比較困難,因?yàn)槊總€(gè)單獨(dú)的底層邏輯服務(wù)器上都只是存放
了自己這一個(gè)服務(wù)器上的用戶數(shù)據(jù),它沒有辦法查找到其它服務(wù)器上的用戶數(shù)據(jù)。解決這個(gè)問題,簡單一點(diǎn)的作法,就是在集群內(nèi)部,由一個(gè)中介者,提供一個(gè)全局
的玩家列表。這個(gè)全局列表,根據(jù)需要,可以直接放在“服務(wù)器管理者”上,也可以存放在數(shù)據(jù)庫中。
對于邏輯相對獨(dú)立的應(yīng)用,全局列表的
使用機(jī)會其實(shí)并不多,最主要的作用就是用來檢測玩家是不是重復(fù)登錄了。但如果有其它的某些應(yīng)用,要使用這樣的全局列表,就會使數(shù)據(jù)同步顯得比較復(fù)雜。比
如,我們在超大無縫地圖的MMORPG里,如果允許跨服操作(如跨服戰(zhàn)斗、跨服交易等)的話,這時(shí)的數(shù)據(jù)同步將會變得異常復(fù)雜,也容易使處理邏輯出現(xiàn)不可
預(yù)測性。
我認(rèn)為,對于休閑平臺而言,QQ游戲的架構(gòu)已經(jīng)是比較合理的,也可以稱之為休閑平臺的標(biāo)準(zhǔn)架構(gòu)了。那么,MMORPG一般的架構(gòu)是什么樣的呢?
MMORPG一般是把整個(gè)游戲分成若干個(gè)游戲世界組,每個(gè)組內(nèi)其實(shí)就是一個(gè)單獨(dú)的游戲世界。而不同的組之間,其數(shù)據(jù)皆是相互獨(dú)立的,并不象QQ休閑平臺
一樣所有的用戶都會有一個(gè)集中的數(shù)據(jù)存放點(diǎn),MMORPG的游戲數(shù)據(jù)是按服務(wù)器組的不同而各自存放的。玩家在登錄QQ游戲時(shí),QQ游戲相關(guān)的服務(wù)器會自動
為玩家的登錄進(jìn)行負(fù)載均衡,選擇相對不忙的服務(wù)器為其執(zhí)行用戶驗(yàn)證并最終讓用戶選擇進(jìn)入哪一個(gè)游戲房間。但是,玩家在登錄MMORPG時(shí),卻沒有這樣的自
動負(fù)載均衡,一般是由玩家人為地去選擇要進(jìn)入哪一個(gè)服務(wù)器組,之所以這樣,是因?yàn)楦鞣?wù)器組之間的數(shù)據(jù)是不相通的。其實(shí),細(xì)致想來,MMORPG的服務(wù)器
架構(gòu)思想與休閑平臺的架構(gòu)思想有異曲同工之妙,MMORPG的思想是:可以為玩家無限地開獨(dú)立的游戲世界(即服務(wù)器組),以滿足大型玩家在線;而休閑平臺
的思想則是:可以為玩家無限地開游戲房間以滿足大量玩家在線。這兩種應(yīng)用,可以無限開的都是“具有完整游戲性的游戲世界”,對于MMORPG而言,它的一
個(gè)完整的游戲地圖就是一個(gè)整體的“游戲世界”,而對于休閑平臺,它的一個(gè)游戲房間就可以描述為一個(gè)“游戲世界”。如果MMORPG作成了休閑平臺那樣的全
服皆通,也不是不可以,但隨之而來的,就是要解決眾多跨服問題,比如:好友、組隊(duì)、幫派等等的問題,所有在傳統(tǒng)MMORPG里所定義的這些玩家組織形式的
規(guī)則可能都會因?yàn)?#8220;全服皆通”而改變。
架構(gòu)的選擇是多樣性的,確實(shí)沒有一種可以稱得上是最好的所謂的架構(gòu),適合于當(dāng)前項(xiàng)目的,不一定就適合于另一個(gè)項(xiàng)目。針對于特定的應(yīng)用,會靈活選用不同的架構(gòu)。但有一點(diǎn),是可以說的:不管你如何架構(gòu),你所要作的就是--要以盡可能簡單的方案實(shí)現(xiàn)盡可能的穩(wěn)定、高效!
posted @
2009-09-23 23:48 暗夜教父 閱讀(758) |
評論 (0) |
編輯 收藏
本文作者:sodme
本文出處:http://blog.csdn.net/sodme
聲明:本文可以不經(jīng)作者同意任意轉(zhuǎn)載,但任何對本文的引用都須注明作者、出處及此聲明信息。謝謝!!
特別聲明:
本人非常欣賞暴雪及他們的游戲,之所以寫這個(gè)文章,是想讓大家了解一些網(wǎng)絡(luò)封包分析方面的常見方法以及學(xué)習(xí)暴雪游戲在網(wǎng)
絡(luò)處理方面的經(jīng)驗(yàn),偶認(rèn)為作為一個(gè)網(wǎng)絡(luò)編程者,熟練掌握封包分析的工具和方法應(yīng)該是其基本功之一。本文所列的所有封包分析內(nèi)容,全部是采用普通黑箱方式即
可得來的,并未涉及對魔獸世界可執(zhí)行程序的逆向工程。同時(shí),除此文涉及的內(nèi)容外,本人拒絕向任何人透露更詳細(xì)的關(guān)于魔獸世界封包方面的更多內(nèi)容,有興趣者
請自己進(jìn)行相關(guān)的試驗(yàn),本人在此文中也將盡量避免公開敏感的封包內(nèi)容及相關(guān)加解密算法。謹(jǐn)以此文獻(xiàn)給忠愛的暴雪!
一、登錄模塊流程及封包分析
我們先看登錄流程。從封包流程來看,魔獸的登錄流程是這樣的:
1.由
Client向登錄/賬號服務(wù)器(Login
Server)發(fā)送用戶名及密碼等信息。此數(shù)據(jù)包的最后部分是用戶名(明文表示,未加密),在用戶名的前一個(gè)字節(jié)表示的是用戶名的長度。登錄/賬號服務(wù)器
向Client返回登錄成功及后續(xù)連接到游戲服務(wù)器服務(wù)器所必備的信息等。這中間的兩個(gè)來往數(shù)據(jù)包,我還沒有看出具體有什么作用。在這個(gè)交互過程中,由登
錄/賬號服務(wù)器向Client發(fā)送所有的游戲服務(wù)器列表,服務(wù)器列表數(shù)據(jù)包的內(nèi)容包括:ip, port,
服務(wù)器上所擁有的角色個(gè)數(shù)等信息,因服務(wù)器列表內(nèi)容過多,被客戶端分為兩次接收完畢。
2.Client收到Login
Server的服務(wù)器列表后,根據(jù)最近訪問的服務(wù)器標(biāo)識(這個(gè)信息應(yīng)該是包含在那個(gè)服務(wù)器列表數(shù)據(jù)包中),連接到最近游戲的那個(gè)游戲服務(wù)器(Game
Server)。連接成功后,Game
Server首先向Client發(fā)送一個(gè)8字節(jié)的數(shù)據(jù)包,據(jù)以往的常識判斷,這個(gè)數(shù)據(jù)包的內(nèi)容很可能是以后客戶端與服務(wù)器通信的加密密鑰。
3.Client向Game Server再次發(fā)送自己的賬號信息。Game
Server與Client經(jīng)過兩個(gè)數(shù)據(jù)包的交互后,向Client發(fā)送角色數(shù)據(jù)包,此包中包括了玩家在該Game
Server所創(chuàng)建的所有角色信息,當(dāng)然這個(gè)信息只是部分的,并不是該角色的所有信息。
4.在此后的通信過程中,Client每隔30秒向Game Server發(fā)送一個(gè)保持連接的包,該包長度為10字節(jié),包的最后四字節(jié)是一個(gè)遞增數(shù)字,前面6字節(jié)暫時(shí)未看出規(guī)律。
5.只要Client沒有點(diǎn)擊某個(gè)角色進(jìn)入最終的Game Server,則Client要始終與Login
Server保持連接。當(dāng)Client點(diǎn)擊角色進(jìn)入Game Server時(shí),Client才與Login
Server斷開連接。在以后的游戲過程中,Client始終與且僅與該Game Server進(jìn)行數(shù)據(jù)通信。
通過對登錄流程中的數(shù)據(jù)包初步分析,可以得出以下幾個(gè)結(jié)論:
1.Client向Login
Server發(fā)的第一個(gè)數(shù)據(jù)包,用戶名部分是采用明文的,且該數(shù)據(jù)包的內(nèi)容,每次登錄都一樣,并沒有因時(shí)間的不同而發(fā)生改變。由此可以推算:針對于此數(shù)據(jù)
包中的密碼加密算法是固定不變的,換句話說,密碼的加密算法是比較容易通過逆向工程被找到的。偶認(rèn)為,針對于此處,服務(wù)器也應(yīng)該先向客戶端發(fā)送一個(gè)加密密
鑰,以后的通信可以用該密鑰作為安全驗(yàn)證的依據(jù)。但暴雪沒有這樣作,最大的可能是為了提高服務(wù)器的效率,在登錄服務(wù)器上,如果每個(gè)客戶端一旦連接成功,登
錄服務(wù)器都得向客戶端廣播一個(gè)數(shù)據(jù)包的話,可能這個(gè)量還是比較大的,這可能延長了玩家的登錄等待時(shí)間,所以他們沒有在這塊作。
2.Client在登錄Login Server的地址,每次Login
Server的登錄地址都可能是不一樣的。偶沒有在客戶端目錄里找到這些地址,只在客戶端目錄里找到了四個(gè)大區(qū)的四個(gè)域名,我猜想,魔獸世界是用的DNS
解析的簡單方法來實(shí)現(xiàn)Login Server的簡單動態(tài)均衡的。不知道這個(gè)猜想是否正確。
3.“根據(jù)玩家最近在玩的哪個(gè)游戲,由客戶端和服務(wù)器自動為玩家選擇進(jìn)入這個(gè)游戲服務(wù)器”,這一項(xiàng)設(shè)定充分體現(xiàn)了暴雪一貫的風(fēng)格:為玩家著想,最大限度地提高游戲的舒適度。再次對暴雪的態(tài)度予以肯定!
4.一旦玩家進(jìn)入了游戲世界,客戶端與服務(wù)器的通信端口會一直保持不變。即:魔獸世界的游戲世界服務(wù)器群設(shè)計(jì)結(jié)構(gòu)采用的是帶網(wǎng)關(guān)的服務(wù)器集群。
5.偶覺得在整個(gè)的登錄流程中,讓我產(chǎn)生最大疑問的就是Login Server與Client的連接保持邏輯。當(dāng)Client與Game
Server連接了之后,Client并未與Login
Server斷開,是一直保持連接的。后來,經(jīng)進(jìn)一步的抓包分析,Client之所以要與Login
Server保持這樣的連接,是為了當(dāng)Client重新選擇服務(wù)器時(shí),不至于重新連接Login
Server。當(dāng)Client點(diǎn)擊了"選擇服務(wù)器"按紐后,Login
Server會每隔5秒向Client發(fā)一個(gè)當(dāng)前所有的服務(wù)器列表數(shù)據(jù)包。要知道,這個(gè)服務(wù)器列表數(shù)據(jù)包的內(nèi)容可是非常大的,如果有玩家就打開了這個(gè)窗口
不關(guān)閉,Login
Server向這種情況的所有玩家每5秒鐘就發(fā)一個(gè)服務(wù)器列表數(shù)據(jù)包,這個(gè)廣播量可是很大的哦(2k左右,這可是一個(gè)用戶是2k哦)。偶認(rèn)為這里的邏輯設(shè)
計(jì)是相當(dāng)不合理的。Login
Server如果為了給客戶端提供一個(gè)最新的全局服務(wù)器列表,可以保持連接,但也沒必要每隔5秒就向客戶端發(fā)一個(gè)服務(wù)器列表,最多只在客戶端在某個(gè)服務(wù)器
上創(chuàng)建了不同的角色后再更新這個(gè)列表也是可以的,但只用更新這個(gè)列表中的變化內(nèi)容即可,不用發(fā)全部的完整包,這樣,在通信量上就小了很多。據(jù)說,魔獸剛開
始的時(shí)候,產(chǎn)生DOWN機(jī)的原因就是登錄模塊沒有處理好,偶不知道現(xiàn)在的這個(gè)情況是不是已經(jīng)經(jīng)過改良的了。但偶還是認(rèn)為每隔5秒就向客戶端發(fā)送一個(gè)2K的
包,這一點(diǎn)是不可以被接受的。
以上只是針對于魔獸世界登錄流程的簡單分析,沒有多少技術(shù)含量,拿出來跟大家相互討論討論,看看有沒有可以借鑒的地方,后面還會有其它部分的封包分析。歡迎繼續(xù)關(guān)注偶的Blog: http://blog.csdn.net/sodme。
偶在文章前面部分說過,作為一個(gè)網(wǎng)絡(luò)編程人員,熟練使用截包軟件和掌握基本的封包分析方法是其基本能力之一,發(fā)此文的目的一個(gè)原因也是希望向正在作網(wǎng)絡(luò)編程的兄弟介紹一下相關(guān)工具的使用和常見的分析方法。下面補(bǔ)充一下關(guān)于封包分析的基本方法和相關(guān)工具:
1.你需要一個(gè)截包工具,偶推薦:commview,小巧但功能強(qiáng)大,支持自定義的封包分析插件以DLL形式裝載,也就是說只要你愿意,你可以寫個(gè)DLL對某類特殊形式的包進(jìn)行顯示、記錄、解密等特別處理。
2.如何查看真正的封包數(shù)據(jù)。在commview里,會詳細(xì)列出自網(wǎng)卡級別以上的各層封包數(shù)據(jù),包括Ethernet層,IP層和TCP層。而我們作封
包分析時(shí),只需要關(guān)注TCP層。但TCP層里也有很多內(nèi)容,對于我們的分析需求來說,我們需要關(guān)注的是其Data字段(在協(xié)議目錄里可以看到"data
length標(biāo)識,點(diǎn)擊即可查看data段")的內(nèi)容。
3.TCP的幾個(gè)狀態(tài)對于我們分析所起的作用。在TCP層,有個(gè)FLAGS字
段,這個(gè)字段有以下幾個(gè)標(biāo)識:SYN, FIN, ACK, PSH, RST,
URG.其中,對于我們?nèi)粘5姆治鲇杏玫木褪乔懊娴奈鍌€(gè)字段。它們的含義是:SYN表示建立連接,F(xiàn)IN表示關(guān)閉連接,ACK表示響應(yīng),PSH表示有
DATA數(shù)據(jù)傳輸,RST表示連接重置。其中,ACK是可能與SYN,F(xiàn)IN等同時(shí)使用的,比如SYN和ACK可能同時(shí)為1,它表示的就是建立連接之后的
響應(yīng),如果只是單個(gè)的一個(gè)SYN,它表示的只是建立連接。TCP的幾次握手就是通過這樣的ACK表現(xiàn)出來的。但SYN與FIN是不會同時(shí)為1的,因?yàn)榍罢?
表示的是建立連接,而后者表示的是斷開連接。RST一般是在FIN之后才會出現(xiàn)為1的情況,表示的是連接重置。一般地,當(dāng)出現(xiàn)FIN包或RST包時(shí),我們
便認(rèn)為客戶端與服務(wù)器端斷開了連接;而當(dāng)出現(xiàn)SYN和SYN+ACK包時(shí),我們認(rèn)為客戶端與服務(wù)器建立了一個(gè)連接。PSH為1的情況,一般只出現(xiàn)在
DATA內(nèi)容不為0的包中,也就是說PSH為1表示的是有真正的TCP數(shù)據(jù)包內(nèi)容被傳遞。TCP的連接建立和連接關(guān)閉,都是通過請求-響應(yīng)的模式完成的。
封包分析的手段,說簡單也挺簡單的,那就是:比較!要不斷地從不同的思維角度對封包進(jìn)行對比分析,要充分發(fā)揮你的想象力不斷地截取自己需要的包進(jìn)行比較。不僅要作橫向(同類)的比較,還要作縱向(不同類)的比較。即時(shí)對于同一個(gè)包,也要不斷地反復(fù)研究。
初涉封包分析的新手,一般會不知道封包分析究竟該從何入手。基于經(jīng)驗(yàn),本文將告訴你一般會從哪些類型的包入手進(jìn)行分析以及應(yīng)該怎樣對封包進(jìn)行初
步的分析。需要指出的是:封包分析是一件非常有趣但同時(shí)也非常考驗(yàn)?zāi)托牡氖拢ǔ#胩斓姆獍治鱿聛恚瑫屇阊矍叭侵T如“B0 EF 58 02
10 72....”之類的網(wǎng)絡(luò)數(shù)據(jù),而且附帶有頭疼、頭暈癥狀,所以,沒有充分的心理準(zhǔn)備,還請不要輕易嘗試。呵呵。
從事封包分析的基本前提是:應(yīng)該了解和熟悉TCP協(xié)議,并知道數(shù)據(jù)包“粘合”是怎么一回事。當(dāng)然,我們平常截獲到的包,從數(shù)量上來看,只有一小
部分是屬于“粘合”的情況。但如果不了解它,將可能會對你的分析思路產(chǎn)生誤導(dǎo)和困惑。關(guān)于“粘包”的更詳細(xì)解釋,請參考我的另外一篇文章“拼包函數(shù)及網(wǎng)絡(luò)
封包的異常處理(含代碼) (http://blog.csdn.net/sodme/archive/2005/07/10/419233.aspx)”。
上一篇有關(guān)魔獸世界封包分析的文章(http://blog.csdn.net/sodme/archive/2005/06/18/397371.aspx)中,我根據(jù)客戶端與服務(wù)器端連接及斷開事件的處理流程以及登錄過程中的一些數(shù)據(jù)包分析了魔獸的架構(gòu)和登錄邏輯。這篇文章中,我將結(jié)合聊天數(shù)據(jù)包的分析,來闡述魔獸世界封包的大體結(jié)構(gòu)。
首先解釋一下我們的目標(biāo):封包的大體結(jié)構(gòu)。封包的大體結(jié)構(gòu)包含哪些內(nèi)容呢?一般情況下,封包的大體結(jié)構(gòu)至少包括兩方面的信息:
1、一個(gè)封包是如何表示它的長度的?封包長度是由哪個(gè)字段表示的?(或者說:如何表示封包的開始和結(jié)束的)
2、各種不同的封包類型是通過哪個(gè)字段表示的?
是不是所有游戲的封包都必然會有表示“長度”信息的“字段”呢?答案是否定的。有的游戲確實(shí)沒有采用這種方式,它們的作法設(shè)定特殊的包開始和包
結(jié)束標(biāo)志。但是,從應(yīng)用的角度來看,偶推薦使用“長度”這樣的方法,因?yàn)椴还茉诰W(wǎng)絡(luò)底層的處理效率以及上層應(yīng)用的處理便捷性來說,使用“長度”字段標(biāo)識一
個(gè)完整的邏輯包都是比較好的辦法。在確定了封包的大體結(jié)構(gòu)后,我們才方便分析具體類型包(比如聊天、行走等)的詳細(xì)結(jié)構(gòu)。
作數(shù)據(jù)包分析,在單純采用黑箱分析的階段,我們選取的數(shù)據(jù)包,須要是具有這種性質(zhì)的,即:在數(shù)據(jù)包發(fā)送前客戶端未進(jìn)行加密等處理時(shí),這個(gè)數(shù)據(jù)包
中的部分內(nèi)容,我們是已經(jīng)知道的。這樣的包,就可以作為封包分析的突破口。這樣看來,我們拿“聊天封包”作為第一個(gè)分析對象也就不難理解了,因?yàn)槲覀冋f的
話,打上去的字,我們自己是知道的,但是我們說的話經(jīng)過客戶端的處理后,發(fā)到網(wǎng)絡(luò)上的可能就是已經(jīng)加了密的或者加了校驗(yàn)碼的。站在黑箱分析的角度,我們能
作的,就是不斷截取各種“聊天包”進(jìn)行對比、判斷和總結(jié)。
OK,打開你的commview。讓我們從“聊天封包”開始。
分析“聊天包”的前提,是我們能夠正常判斷哪種類型的數(shù)據(jù)包是屬于聊天的,不要誤把行走或其它的數(shù)據(jù)包當(dāng)作了聊天數(shù)據(jù)包。為了減小分析難度,建
議新手到游戲中人少或周圍沒有玩家的地方進(jìn)行封包分析。這樣一來沒人打擾,二來你的網(wǎng)絡(luò)通信量會相對小得多,比較容易進(jìn)行一些封包判定。
第一步,我們需要確定客戶端與服務(wù)器通信所用的端口,然后在commview的rules->ports中設(shè)定服務(wù)器端口,截獲與該端口
通信的所有數(shù)據(jù)包。服務(wù)器端口的確定方法:不要使用其它網(wǎng)絡(luò)通信工具,打開commview,進(jìn)游戲,截包,觀察其通信端口。進(jìn)行封包分析時(shí),特別是初期
的封包分析時(shí),你的網(wǎng)絡(luò)通信應(yīng)該盡可能是單一的,即:除了游戲,其它的通信軟件盡可能不要開。但當(dāng)你確定了服務(wù)器的IP和端口后,就可以照常使用其它網(wǎng)絡(luò)
軟件了。
第二步,如前面述,在游戲中找個(gè)人少或沒人的地方,開始“自言自語”,呵呵。說話的內(nèi)容,建議以字母和數(shù)字為宜,不要說中文。因?yàn)橹形氖请p字節(jié)
的,而字母和數(shù)字是單字節(jié)的,對于單字節(jié)的信息內(nèi)容,截包軟件會以單字節(jié)的文本信息顯示,但對于雙字節(jié)的漢字而言,截包軟件在對其進(jìn)行顯示時(shí)由于換行等原
因會造成部分中文顯示有亂碼,不容易直接看出中文內(nèi)容。如果執(zhí)意要說中文,偶也不攔你,給你推薦一個(gè)工具:String Demander(下載地址:http://www.cnxhacker.com/Download/show/395.html),這個(gè)軟件,可以查詢中文所對應(yīng)的編碼。
第三步,設(shè)定好commview的rules并使之生效,開始截包。
觀察通過以上的過程所截的包,可以發(fā)現(xiàn),魔獸世界的聊天封包的說話內(nèi)容是明文的!這一點(diǎn),用不著大驚小怪,呵呵。聊天封包本身并不會對游戲的關(guān)
鍵邏輯造成損害,所以,即使讓其明文顯示也不足為奇。但是,我們還是不太相信自己的眼睛,于是再截若干個(gè)包,發(fā)現(xiàn)包中的說話內(nèi)容確實(shí)是明文的!但是,包的
其它字段卻是我們一時(shí)看不懂的“密文”。
看來,下面的事情就是對這些包里的“密文”進(jìn)行研究了。一般情況下,這種“密文”的加密方法,通過封包分析是分析不出來的,但,我們?nèi)匀豢梢酝ㄟ^封包分析來推論一些與“密文”生成算法有關(guān)的問題。我們可以作以下的對比分析:
1、連續(xù)三次輸入“a”,并分別觀察及保存封包數(shù)據(jù);
2、連續(xù)三次輸入“aa”,并分別觀察及保存封包數(shù)據(jù);
3、連續(xù)三次輸入“aaa”,并分別觀察及保存封包數(shù)據(jù)。
輸入的封包用例,我們選擇了字母"a",它的ASCII碼是61。輸入的規(guī)律是:每種情況連續(xù)輸入三次,然后逐次增加a字母的個(gè)數(shù)。于是,我們發(fā)現(xiàn)這樣一個(gè)有趣的現(xiàn)象:
1、包中有關(guān)說話的內(nèi)容是明文的;
2、即使針對于同樣的說話內(nèi)容,比如“a”,客戶端所發(fā)出去的包也是不一樣的;
3、當(dāng)一次說話的字母個(gè)數(shù)增加1時(shí),封包的總體長度也隨之增加1;
4、除每個(gè)封包的前面6個(gè)字節(jié)以及說話的字節(jié)外,其余的封包內(nèi)容每次都一樣;
5、每個(gè)聊天封包的結(jié)尾字節(jié)都是0。
于是,我們可以試著得出如下結(jié)論:
1、包是沒有壓縮的,它所使用的加密算法應(yīng)該是按字節(jié)進(jìn)行的,并沒有改變封包的長度使之看上去使用統(tǒng)一的長度;
2、包是以0結(jié)尾的(盡管我們不知道它是以什么表示開頭的,呵呵);
3、封包加密算法中所使用的密鑰是可變的,即針對于相同的數(shù)據(jù)包內(nèi)容由于加密的密鑰不同,所以產(chǎn)生的密文也不同。由于客戶端的數(shù)據(jù)傳到服務(wù)器端后,服務(wù)
器端還要對數(shù)據(jù)進(jìn)行解密。所以,客戶端的加密算法與服務(wù)器端的解密算法應(yīng)該共用了前6字節(jié)中的某些內(nèi)容,以此作為解密算法的密鑰。如果這6字節(jié)中沒有包含
有關(guān)封包加、解密所需要的同步數(shù)據(jù),那客戶端和服務(wù)器之間應(yīng)該會通過其它的方式同步這樣的數(shù)據(jù)。不過,偶傾向于前者,即:這6字節(jié)中應(yīng)該含有加、解密所需
要的密鑰信息。
回頭看我們上面觀察到的有趣現(xiàn)象,針對于第2點(diǎn),反過來想,這應(yīng)該也是最起碼的功能了。就是說,即使客戶端作出的是同樣的動作,在客戶端發(fā)出的包中,包的內(nèi)容也是不一樣的。這樣,外掛就不能靠單純的重復(fù)發(fā)相同的包而達(dá)到其目的了。
分析來分析去,我們還是沒能確定魔獸封包的大體結(jié)構(gòu)。其實(shí),到現(xiàn)在,我覺得我此文的目的已經(jīng)達(dá)到了,即向大家展示封包分析的思維角度和思維方
式。至于具體結(jié)果,偶覺得倒真的不重要的了。可以肯定地告訴大家的是,魔獸的封包結(jié)構(gòu)偶大致已經(jīng)掌握了。偶僅在此公布我的分析結(jié)果:
1、魔獸的封包長度字段是每個(gè)封包的前兩字節(jié),它的表示方式是:前兩字節(jié)的數(shù)值+2。之所以加這個(gè)2,是因?yàn)榉獍L度字段本身占用了兩個(gè)字節(jié)的長度。
2、魔獸的封包類型偶推斷是第三和第四字節(jié),其中普通聊天的類型標(biāo)識是“95 00”。
請不要來信向我詢問任何有關(guān)魔獸封包破解的內(nèi)容,偶能說的都已經(jīng)在文章里說了,偶之所以寫這個(gè)系列的文章不是想破解魔獸,而是想以這樣優(yōu)秀的一
款游戲作為案例來向大家展示它在封包設(shè)計(jì)方面值得我們學(xué)習(xí)和討論的地方,同時(shí)向更多的朋友普及有關(guān)封包分析的常識、工具以及思維方式,僅此而已。
ps:由于每次封包分析的內(nèi)容都很多,所以,一有了點(diǎn)結(jié)論后,要及時(shí)記錄和總結(jié),并與之前取得的總結(jié)進(jìn)行對比,及時(shí)更新相關(guān)的記錄文檔。
posted @
2009-09-23 23:48 暗夜教父 閱讀(831) |
評論 (0) |
編輯 收藏