教父的告白
一切都是纸老虎
posts - 82,  comments - 7,  trackbacks - 0

VS2008Sp1+SilverLight3+Blend3

首先安装Visual Studio 2008 专业版(只要空间够,与VS2005共存完全没有问题),打上 Microsoft Visual Studio 2008 Service Pack 1。安装Sp1的时候可能花的时间有点久,>=安装VS2008的时间,考验耐心的时间到了。。

要注意的是电脑里有的是VS2008 Beta ,那就麻烦 了,升级到VS2008正式版比想象中的困难,实在不行就只能用第2种组合了。

下面就开始配置SilverLight了,首先安装

Microsoft® Silverlight™ 3 Tools for Visual Studio 2008 SP1

,注意语言选择要与VS2008的对应。

接着是Silverlight 3 Toolkit July 2009,Xaml的界面设计Microsoft Expression Blend 3 Preview目前只有英文版,所有的都用最新的尝尝鲜。。

VS2010Beta 1+SilverLight2+SilverLight3

vs2010Beta1是基于WPF的,因此界面与很多新特性比以前看起来是舒服多了,不过性能方面那就严重地有待提高,无响应的几率相对于 VS2008至少增加了20%。安装过程中会重启(Framework 4),镜像只有1288M,但安装系统盘的大小基本要求还是很高的,曾经试过最小也要2.4G。

SilverLight2自带就已经安装了,但现在还不能创建SL2的项目并且F5调试的时候也会报Debug manage,这时就要安装依次下面的的就可以OK了

Microsoft® Silverlight™ 2 软件开发工具包

Microsoft® Silverlight™ 3 SDK

Silverlight.3.0_Developer

。在装Silverlight.3.0_Developer安装的过程中可能会提示已经安装更新版本,老老实实去卸载吧Silverlight3吧,不然调试功能就没有机会享用 了。。

至此为止,以上两种组合的SilverLight开发环境已经完成了,希望对大家有帮助。下次将发布“使用Silverlight技术,Bing搜索API和远端WCF/WPF实现Ink手写搜索框”开发过程与源码。

posted @ 2009-10-22 12:25 暗夜教父 阅读(288) | 评论 (0)编辑 收藏

apt-get 使用指南

原文出处:https://help.ubuntu.com/community/AptGetHowto

原文作者:UbuntuWiki

授权许可:

  • 创作共享协议Attribution-ShareAlike 2.0
  • GNU自由文档许可证

翻译人员:sigus 5451vs5451 youyou keke initnas

校正人员:MillenniumDark


适用版本:

文章状态:等待校正


IconsPage?action=AttachFile&do=get&target=IconApt.png apt-get使用source.list文件进行软件包管理。如果您想了解关于如何编辑和更新source.list中的条目的信息,请参阅SourcesList

引言

“起初GNU/Linux系 统中只有.tar.gz。用户必须自己编译他们想使用的每一个程序。在Debian出现之後,人们认为有必要在系统中添加一种机制用来管理安装在计算机上 的软件包。人们将这套系统称为dpkg。至此着名的‘package’首次在GNU/Linux上出现。不久之後红帽子也开始着手建立自己的包管理系统 ‘rpm’。

“GNU/Linux的创造 者们很快又陷入了新的窘境。他们希望通过一种快捷、实用而且高效的方式来安装软件包。这些软件包可以自动处理相互之间的依赖关系,并且在升级过程中维护他 们的配置文件。Debian又一次充当了开路先锋的角色。她首创了APT(Advanced Packaging Tool)。这一工具後来被Conectiva 移植到红帽子系统中用于对rpm包的管理。在其他一些发行版中我们也能看到她的身影。”

"同时,apt是一个很完整和先进的软件包管理程序,使用它可以让你,又简单,又准确的找到你要的的软件包, 并且安装或卸载都很简洁。 它还可以让你的所有软件都更新到最新状态,而且也可以用来对ubuntu进行升级。"

"apt是需要用命令来操作的软件,不过现在也出现了很多有图形的软件,比如Synaptic, Kynaptic 和 Adept。"

 命令

下面将要介绍的所有命令都需要sudo!使用时请将“packagename”和“string”替换成您想要安装或者查找的程序。

apt-get autoclean——定期运行这个命令来清除那些已经卸载的软件包的.deb文件。通过这种方式,您可以释放大量的磁盘空间。如果您的需求十分迫切,可以使用apt-get clean以释放更多空间。这个命令会将已安装软件包裹的.deb文件一并删除。大多数情况下您不会再用到这些.debs文件,因此如果您为磁盘空间不足而感到焦头烂额,这个办法也许值得一试。

典型应用

我是个赛车发烧友,想装个赛车类游戏玩玩。有哪些赛车类游戏可供选择呢?

apt-cache search racing game

出来了一大堆结果。看看有没有更多关于torcs这个游戏的信息。

apt-cache show torcs

看上去不错。这个游戏是不是已经安装了?最新版本是多少?它属于哪一类软件,universe还是main?

apt-cache policy torcs

好吧,现在我要来安装它!

apt-get install torcs

在 控制台下我应该调用什么命令来运行这个游戏呢?在这个例子中,直接用torcs就行了,但并不是每次都这么简单。我们可一通过查找哪些文件被安装到了 “/usr/bin”文件夹下来确定二进制文件名。对于游戏软件,这些二进制文件将被安装到“/usr/games”下面。对于系统管理工具相应的文件夹 是“/usr/sbin”。

dpkg -L torcs|grep /usr/games/

这个命令的前面一部分显示软件包“torcs”安装的所有文件(您自己试试看)。通过命令的第二部分,我们告诉系统只显示前一部分的输出结果中含有“/usr/games”的那些行。

这个游戏很酷哦。说不定还有其他赛道可玩的?

apt-cache search torcs

我的磁盘空间不够用了。我得把apt的缓存空间清空才行。

apt-get clean

哦不,老妈叫我把机器上的所有游戏都删掉。但是我想把配置文件保留下来,这样待会我只要重装一下就可以继续玩了。

apt-get remove torcs

如果我想连配置文件一块删除:

apt-get remove --purge torcs

额外的软件包

deborphan和debfoster工具可以找出已经安装在系统上的不会被用到的软件包。

 提高命令行方式下的工作效率

您可以通过定义别名(alias)来提高这些命令的输入速度。例如,您可以在您的*~/.bashrc*文件中添加下列内容

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设置http代理

可以通过三种方法为apt-get设置http代理

方法一

这是一种临时的手段,如果您仅仅是暂时需要通过http代理使用apt-get,您可以使用这种方式。

在使用apt-get之前,在终端中输入以下命令(根据您的实际情况替换yourproxyaddress和proxyport)。

export http_proxy=http://yourproxyaddress:proxyport

方法二

这种方法要用到/etc/apt/文件夹下的apt.conf文件。如果您希望apt-get(而不是其他应用程序)一直使用http代理,您可以使用这种方式。

注意: 某些情况下,系统安装过程中没有建立apt配置文件。下面的操作将视情况修改现有的配置文件或者新建配置文件。

sudo gedit /etc/apt/apt.conf

在您的apt.conf文件中加入下面这行(根据你的实际情况替换yourproxyaddress和proxyport)。

Acquire::http::Proxy "http://yourproxyaddress:proxyport";

保存apt.conf文件。

方法三

这种方法会在您的主目录下的.bashrc文件中添加两行。如果您希望apt-get和其他应用程序如wget等都使用http代理,您可以使用这种方式。

gedit ~/.bashrc

在您的.bashrc文件末尾添加如下内容(根据你的实际情况替换yourproxyaddress和proxyport)。

http_proxy=http://yourproxyaddress:proxyport
export http_proxy

保存文件。关闭当前终端,然後打开另一个终端。

使用apt-get update或者任何您想用的网络工具测试代理。我使用firestarter查看活动的网络连接。

如果您为了纠正错误而再次修改了配置文件,记得关闭终端并重新打开,否自新的设置不会生效。

posted @ 2009-10-19 10:59 暗夜教父 阅读(357) | 评论 (0)编辑 收藏

如果想封掉国内ip或者封掉国外ip,总归要现有国内的ip段才可以。如果要做dns智能解析,也要有各地各运营商的ip段才行。网上有很多各式各样的ip表,但很多都过期了,也不全。如果要做一个比较完整的ip数据,还是要靠APNIC才行。
亚太互联网络信息中心(Asia-Pacific Network InformationCenter,简称APNIC)坐落于澳大利亚的布里斯班,是全球现有4个地区性互联网注册管理机构(RIR)之一,负责向亚太地区64个经济体提供IP(v4及v6)地址和自治系统(AS)号码分配,以及反向DNS授权服务的非营利性会员组织。其会员单位包括ISP、国家(或地区)互联网注册管理机构(NIR)等互联网组织。
如果要找出国内的ip地址段,这个比较简单
国家IP段数据下载地址:http://ftp.apnic.net/apnic/dbase/data/country-ipv4.lst
下载数据后,将国家为cn的ip挑出来自己处理一下就可以。
如果要找出各地各运营商的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地址段;
中国网通:
./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

打开获取后的文件可以看到里面的信息非常详细,甚至可以看到各个分公司的负责人、电话、电子邮件等等信息。如果想得到一份整齐干净的IP地址段文件,只要用grep和awk简单过滤就可以了

然后在apache中设置一下权限就可以。


Order deny,allow
Deny from 113.0.0.0/13
……………………………….
Deny from 61.240.0.0/14

posted @ 2009-10-17 00:41 暗夜教父 阅读(304) | 评论 (0)编辑 收藏

我用的是lamp集成环境是xampp,linux下是lampp,其实都是一个东西。

想改变一下自己老土的调试方式,所以试用一下zend debugger和xdebug

言归正传,如何让三者共存呢。(理论上,你用zend debugger就不必再使用xdebug,反之亦然)

xampp已经给好了zend optimizer的配置,并且xdebug也已经默认给配置好了,只是都没有启用而已

第一步:启用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

这里是一个需要注意的地方

下载zend debugger: 地址:http://downloads.zend.com/pdt/server-debugger/,下载符合你操作系统的版本, 保存到自定义的目录,例如d:/xampp/php/zenddebugger

在该目录下建立一个相应当前php版本的文件夹, 如当前php版本php5.26, 即在该文件夹下建立php-5.2.x文件夹, 注: 此处X为真实的字符,而不是一个代表符。

将下载的debugger中相应版本的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

我们可以以扩展形式加载xdebug,就避免了和zend optimizer冲突。

extension=php_xdebug.dll

注意php_xdebug.dll要在xampp/php/ext目录下

然后php.ini中添加的内容 (xampp已经添加好,我们只需要去掉注释即可)

[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。 开始测试

结果是,zend debugger可以和zend optimize共存,但xdebug不能和zend optimize共存

如果使用dll方式加载xdebug,会有错误提示。并且不再执行

posted @ 2009-10-12 15:43 暗夜教父 阅读(1259) | 评论 (0)编辑 收藏

为啥要PATCH?

    Mnesia最大的缺陷是存储限制。这不是数据库系统的错误,因为Mnesia能够控制虚拟数据的大小。主要的问题在于过时的Erlang DETS存储引擎,速度慢并且使用的32位偏移量(限制单文件大小为2GB)。

思路?

    超乎想象的 mnesia 补丁包 mnesiaex 。这个东西解除了加在 mnesia 数据库系统上所有的限制(虽说上面已经提到,实际上 mnesia 代码本身没有什么真正的限制)——你现在可以用 SleepyCat/BerkeleyDB/MySQL/Amazon S3/Tokyo Cabinet/… 甚至是你自己喜欢的某种东西来当作 mnesia 的后端,就像 ets/dets 一样。而访问的接口仍保持不变——继续沿用 mnesia 的接口,一行也不用改。 DIY 这种扩展也变得相当容易,写一个 behavior 就成了。

实现过程

1:与从源代码编译的方式安装Erlang

tar xvf otp_src_R12B-5.tar.gz

cd otp_src_R12B-5

./configure & make & make install

注意:我的系统是RHEL 5.3,默认安装目录为/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博客,转载请标明出处:http://blog.csdn.net/jimmychou/archive/2009/03/13/3988468.aspx

posted @ 2009-09-29 15:12 暗夜教父 阅读(873) | 评论 (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实现的细节和与性能与伸缩性相关一些简单介绍。

几周之内还有有一个关于多核如何运作以及未来如何发展的更详细的介绍。我打算将一些内容放在我的报告中,将于9月27日的ICFP2008,Erlang Workshop在Victoria BC展示给大家。

没有SMP支持的Erlang VM只有1个运行在主处理线程中的调度器。该调度器从运行队列(run-queue)中取出可以运行的Erlang进程以及IO任务,而且因为只有一个线程访问他们所以无须锁定任何数据。

而带有SMP支持的Erlang VM可以有一个或多个调度器,每个运行在一个线程中。调度器从同一个公共运行队列中取出可运行的Erlang进程和IO任务。在SMP VM中所有的共享数据结构都会由锁进行保护,运行队列就是这样一个由锁保护的数据结构。

从OTP R12B开始,如果操作系统报告有多于1个的CPU(或者核心)VM的SMP版本会自动启动,并且根据CPU或者核心的数量启动同样数量的调度器。

你可以从“erl”命令打印出来的第一行看到它选择了哪些参数。例如:


Erlang (BEAM) emulator version 5.6.4 [source] [smp:4] [asynch-threads:0] …..
其中“[smp:4]”表示SMP VM运行了4个调度器。

默认值可以用“-smp [enable|disable|auto]”来替换,auto是默认的。如果smp被启用了(-smp enable),要设置调度器的数量可以使用“+S Number”其中Number是调度器的数量(1到1024)

注意1:运行多于CPU或核心总数的调度器不会有任何提升。

注意2:在某些操作系统中一个进程可使用的CPU或者核心的数量可以被限制。例如,在Linux中,命令“taskset”就可以实现这个功能。 Erlang VM目前还只能探测CPU或者核心的总数,不会考虑“taskset”所设置的掩码。正因如此,例如可能会出现(已经出现过了)即使Erlang VM运行了4个调度器,也只使用了2个核心。OS会进行限制因为它要考虑“taskset”所设置的掩码。

每个Erlang VM的调度器都运行于一个OS线程上,是OS来决定线程是否执行在不同的核心上。一般来说OS会很好地处理这个问题并且会保证线程在执行期间运行于同一个核心上。

Erlang进程会被不同的调度器运行,因为他们是从一个公共运行队列中被取出,由首先可用的调度器运行。

性能和伸缩性

只有一个调度器的SMP VM要比非SMP的VM稍微慢那么一点点。SMP VM内部需要用到各种锁,不过只要不存在锁的争用,那么由锁引起的开销不会非常大(就是锁争用上面需要花时间)。这也解释了为何在某些情况下,运行多个只有一个调度器的SMP VM要比包含多个调度器的单一SMP VM更加高效。当然运行多个VM要求应用可以按照多个并行任务的方式运行并且之间没有或者几乎不通讯。

一个程序是否能在多核上的SMP VM中良好地进行提升很大程度上取决于程序的性质,某些程序可以保持线性提升至8核甚至16核,同时其他某些程序基本不能提升,连2核都不行。实际应用中很多程序都能在主流市场的核心数上得到提升,见下文。

若并行的持续“通话”由每个核心一个或多个Erlang进程来表示,实际的支持大量通话的电信产品已经先现出在双核和四核处理器上不俗的伸缩性。注意,这些产品是在SMP VM和多核处理器出现很久以前按照普通的Erlang风格来写的,他们也能无须任何修改甚至不需重新编译代码就能从Erlang SMP VM中获益。

SMP性能得到持续改进

SMP实现正被不断改进以便能得到更好的性能和伸缩性。在每个服务发布版R12B-1,2,3,4,5…,R13B等等中,你都能发现新的优化。

一些已知的瓶颈

单一的常见运行队列随着CPU或核心的数量的增加会成为一个显著的瓶颈。

这从4核开始往上就会显现出来,不过4核仍然可以为多数应用程序提供不错的性能。我们正在从事一个每个调度器一个运行队列的解决方法作为目前最重要的改进。

Ets表格会引入锁。在R12B-4之前在每次对一个ets-table的访问中会用到两个锁,但是在R12B-4中meta-table的锁被优化过,可以显著减少争用(前面已经提到争用是有很大代价的)。如果很多Erlang进程访问同一个表格,就会有很多锁争用造成性能降低尤其当这些进程主要工作是访问ets-table。锁存在于表级而非记录级。注意!这也会影响到Mnesia因为Mnesia用到了很多ets-table。

我们关于SMP的策略

当我们开始实现SMP VM的最初,我们就确定了策略:“首先让它可以运行,然后测量,然后优化”。自从2006年五月我们发布了第一个稳定的SMP VM(R11B)以来,我们一直遵循着这个策略。

还有更多已知的东西可以改进,我们会按照性能的收益大小先后各个击破。

我们将主要的精力放在多核(大于4)上更好的连续伸缩性上。

卓越典范

即使SMP系统有还有一些已知的瓶颈不过已经有不错的整体性能和伸缩性,同时我相信在让程序员利用多核机器事半功倍方面,我们是一个卓越的典范。

posted @ 2009-09-24 22:23 暗夜教父 阅读(540) | 评论 (0)编辑 收藏
以下是在erlang项目开发中的一些记录,即包含很多通俗易懂的原则,也包含一些似是而非的建议,比较混乱,还没有积累到一个可以分门别类的地步,各位就将就看吧..
:)

* 确保没有任何编译警告

* Erlang中String采用list实现,32位系统中,其1个字符用8个字节的空间(4个保存value, 4个保存指针)。因此string速度较慢,空间占用较大

* 在Server中,总是尽力书写尾递归(tail-recursive)的函数

* 使用'++'时,left list会被拷贝,然后添加到right list的头部,因此最好把length较短的list放在左侧

* 避免使用regexp,如果需要正则表达式,请使用re

* timer模块的大部分函数实现,依赖于一个process,如果过多使用timer,会导致这个process负载过大,影响效率。
  推荐使用erlang:send_after/3及erlang:start_timer/3

* 避免使用list_to_atom/1,因为erlang中atom数量最大为1048576, 且不进行GC控制。因此如果持续性的调用list_to_atom/1
  可能很容易达到系统上限,从而导致emulator terminate。请使用list_to_existing_atom/1。

* list内部实现为一个列表,因此length(List), 需要遍历整个list比较耗时

* 对于不同的数据类型,使用不同的size函数:tuple_size/1, byte_size/1, bit_size/1

* 使用binary match来进行binary的分割,而不使用split_binary/2

* 如果两个list都拥有很多数据,那么请不要使用'--',而是将数据转化到ordsets,然后调用ordsets:substract/2.

* 对于binary相关操作可以进行binary优化(bin_opt_info编译选项)代码框架:

*   f(<<Pattern1,...,Rest/bits>>,...) -> 
       ... % Rest is not used here 
       f(Rest,...); 
    f(<<Pattern2,...,Rest/bits>>,...) -> 
      ... % Rest is not used here 
      f(Rest,...); 
    ... 
    f(<<>>, ...) -> 
      ReturnValue.

* 调用lists:flatten/1可以将list扁平化,这个操作代价很大,比'++'还要昂贵。下面这些时候我们可以避免:
    将数据发送给port时
    调用list_bo_binary/1和iolist_to_binary前

* 小的函数可以让您方便的找出错误的函数和代码

* 不要在同一行出现相同的符号
20    some_fun() ->
21       L = [{key1, v1}, {key2, [some_record#v21, v22]}],
22      ...
编译时,会提示line 21 '[' 语法错误, 因为21行有多个 '[' ,所以这个bug不能准确定位,你需要花时间去排查代码。
好的做法是:
20 some_fun() ->
21      L = [{key1, v1},
22            {key2, [some_record#v21, v22]}
23            ],
      ...
这样,编译其会提示你 line 22 '[' 语法错误,你很开就知道是那个地方错了。

* 使用 CTRL + \ 或 init:stop(), 可以退出Erlang, 使用CTRL + G 及 CTRL + C 弹出菜单选项,可以选择是否退出Erlang
其中CTRL + G可以用来连接其他的shell, CTRL + C可以查看其他一些系统信息
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冲突现象(sticky)

* epmd -d -d 启动 epmd 可以查看erlang node之间的通讯

* 将正常的逻辑代码和错误处理代码分离,发生错误时,尽管错误。由另一个错误处理模块进行处理

* 类似于操作系统,我们的程序也可以分为kernel 和 user 两层, 对于kernel绝对不能出现错误, 对于user可以出现错误,进行恢复

* process顶层loop涉及的代码及函数,最好在一个module中实现

* process 的register name和module名称一致, 便于寻找代码

* 每个process具有一个单一的角色,比如:supervisor 用来进行错误恢复, work 工作者,可以出现错误, trusted worker 不会出现错误

* 通过函数调用可以实现的功能,就不要使用sever实现(如gen_server, 及类似的loop 实现)

* 给消息加一个tag,在发生错误的时候,可以定位到消息,同时也有利于程序的稳健

* 在消息循环中,对于unknown的消息,请调用lib:flush_receive/0 将其清除,减轻process msg queue的长度

* server中总是书写尾递归的循环

* 尽量使用record, 而不是原始的tuple来表现数据结构, 在使用record时,使用select match:
#person{name = Name, age = Age} = Person

* 对于返回值,最好也添加一个tag,用来说明返回值类型,或者执行成功与否

* 尽可能少的使用catch和try,在erlang程序中,不推荐主动捕获异常。只有当我们的逻辑特别复杂,我们可以使用throw来返回数据,使用catch来获取返回值。

* 当然程序与外界交互,外界数据不可靠时,需要使用catch和try

* 慎重使用process dictory, 当你使用get/1, put/1时,你的应用会具有很大的slide effect。可以通过加入一个新的参数来保存原本需要存储到process dictory中数据

* 如果不想使自己糊涂,请不要使用import

* 使用export时,将功能类似的接口组合在一起,并添加合理的注视,这样你的接口更清晰,别人使用起来更方便

* 不要书写嵌套太深的代码

* 不要书写太长的module

* 不要书写太长的函数

* 每行代码不能太长

* 避免使用 "_" 匿名变量,请为每个变量选择有意义的名称,如够某个变量暂时不使用,请以下划线 "_" 开始

* {error, enfile} enfile error in socket 是以为内linux系统中 ulimit 限制, 在root下修改:ulimit -n 25000

* {error, enotconn} 表示socket已经关闭

* 在erlang开发时,慎重使用macro,因为erlang的single assign的缘故,同时调用某个marco,而macro又定义了某个变量,可能导致badmatch错误。
比如:
-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)).
如果连续使用 WARN, 会出现此错误

* erlang中可以定义很多环境变量:
ERL_MAX_ETS_TABLES 设置最大的ets数目 默认1400
ERL_MAX_PORTS erlang最大的port数目 默认1024

* .app文件中的start_phases, 选项既可以用来作为include applications之间的同步启动,也可以用来对单个application进行分布启动。
顺序如下
包含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

* 任何时候,都要重视函数的返回值,通过match确保您的预期,如果发生错误,那么就大胆的表达出来。
posted @ 2009-09-24 01:00 暗夜教父 阅读(590) | 评论 (0)编辑 收藏
A Million-user Comet Application with Mochiweb, Part 1
在MacOSX平台上遇到的一些问题:

一. IPv6导致的问题
在MacOS下测试时报错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模式的,当测试程序通过http模块连接localhost时,连接的地址是IPv6的::1地址,但是mochi没有在此监听,所以连接出错 {error,econnrefused}

解决方法两种:
1. 将mochi-urls.txt中的地址都改成127.0.0.1
2. 在http:request(…)运行之前调用http:set_options([{ipv6,disabled}]),关闭测试程序的IPv6模式,使用IPv4模式

理论上还有一种方法:让mochi服务器开启IPv6模式监听,这个我不知道这么开,
参考
You should teach Yaws to listen also on IPv6 - “localhost” resolves not
only to IPv4 127.0.0.1, but also to IPv6 ::1.


二. 进程能打开的文件描述符数量的限制
MacOSX下缺省能同时打开的文件描述符最大数是256个,使用 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设置,但最大数量还是不能超过10240

查看内核每进程最大文件数:
$ sysctl kern.maxfiles kern.maxfilesperproc
kern.maxfiles: 12288
kern.maxfilesperproc: 10240

增大每进程最大文件数:
$ sudo sysctl -w kern.maxfilesperproc=20480 kern.maxfiles=22528

然后设置
$ ulimit -n 20480
注意ulimit只在每个shell窗口生命周期内有效,当新开一个shell后,得再次设置
sysctl做的修改没有这个问题

三、调节IP端口号范围,不然最多只能有15K个连接
缺省动态端口号从49152开始,改成2000后最多可以有63K个连接
sysctl -w net.inet.ip.portrange.hifirst=2000 net.inet.ip.portrange.first=2000
posted @ 2009-09-24 00:59 暗夜教父 阅读(403) | 评论 (0)编辑 收藏

本文作者:sodme
本文出处:http://blog.csdn.net/sodme
声明:本文可以不经作者同意任意转载,但任何对本文的引用都须注明作者、出处及此声明信息。谢谢!!

  特别声明:
  本人非常欣赏暴雪及他们的游戏,之所以写这个文章,是想让大家了解一些网络封包分析方面的常见方法以及学习暴雪游戏在网 络处理方面的经验,偶认为作为一个网络编程者,熟练掌握封包分析的工具和方法应该是其基本功之一。本文所列的所有封包分析内容,全部是采用普通黑箱方式即 可得来的,并未涉及对魔兽世界可执行程序的逆向工程。同时,除此文涉及的内容外,本人拒绝向任何人透露更详细的关于魔兽世界封包方面的更多内容,有兴趣者 请自己进行相关的试验,本人在此文中也将尽量避免公开敏感的封包内容及相关加解密算法。谨以此文献给忠爱的暴雪!

  一、登录模块流程及封包分析

  我们先看登录流程。从封包流程来看,魔兽的登录流程是这样的:

  1.由 Client向登录/账号服务器(Login Server)发送用户名及密码等信息。此数据包的最后部分是用户名(明文表示,未加密),在用户名的前一个字节表示的是用户名的长度。登录/账号服务器 向Client返回登录成功及后续连接到游戏服务器服务器所必备的信息等。这中间的两个来往数据包,我还没有看出具体有什么作用。在这个交互过程中,由登 录/账号服务器向Client发送所有的游戏服务器列表,服务器列表数据包的内容包括:ip, port, 服务器上所拥有的角色个数等信息,因服务器列表内容过多,被客户端分为两次接收完毕。

  2.Client收到Login Server的服务器列表后,根据最近访问的服务器标识(这个信息应该是包含在那个服务器列表数据包中),连接到最近游戏的那个游戏服务器(Game Server)。连接成功后,Game Server首先向Client发送一个8字节的数据包,据以往的常识判断,这个数据包的内容很可能是以后客户端与服务器通信的加密密钥。

3.Client向Game Server再次发送自己的账号信息。Game Server与Client经过两个数据包的交互后,向Client发送角色数据包,此包中包括了玩家在该Game Server所创建的所有角色信息,当然这个信息只是部分的,并不是该角色的所有信息。

  4.在此后的通信过程中,Client每隔30秒向Game Server发送一个保持连接的包,该包长度为10字节,包的最后四字节是一个递增数字,前面6字节暂时未看出规律。

5.只要Client没有点击某个角色进入最终的Game Server,则Client要始终与Login Server保持连接。当Client点击角色进入Game Server时,Client才与Login Server断开连接。在以后的游戏过程中,Client始终与且仅与该Game Server进行数据通信。

  通过对登录流程中的数据包初步分析,可以得出以下几个结论:
  1.Client向Login Server发的第一个数据包,用户名部分是采用明文的,且该数据包的内容,每次登录都一样,并没有因时间的不同而发生改变。由此可以推算:针对于此数据 包中的密码加密算法是固定不变的,换句话说,密码的加密算法是比较容易通过逆向工程被找到的。偶认为,针对于此处,服务器也应该先向客户端发送一个加密密 钥,以后的通信可以用该密钥作为安全验证的依据。但暴雪没有这样作,最大的可能是为了提高服务器的效率,在登录服务器上,如果每个客户端一旦连接成功,登 录服务器都得向客户端广播一个数据包的话,可能这个量还是比较大的,这可能延长了玩家的登录等待时间,所以他们没有在这块作。

2.Client在登录Login Server的地址,每次Login Server的登录地址都可能是不一样的。偶没有在客户端目录里找到这些地址,只在客户端目录里找到了四个大区的四个域名,我猜想,魔兽世界是用的DNS 解析的简单方法来实现Login Server的简单动态均衡的。不知道这个猜想是否正确。

  3.“根据玩家最近在玩的哪个游戏,由客户端和服务器自动为玩家选择进入这个游戏服务器”,这一项设定充分体现了暴雪一贯的风格:为玩家着想,最大限度地提高游戏的舒适度。再次对暴雪的态度予以肯定!

  4.一旦玩家进入了游戏世界,客户端与服务器的通信端口会一直保持不变。即:魔兽世界的游戏世界服务器群设计结构采用的是带网关的服务器集群。

5.偶觉得在整个的登录流程中,让我产生最大疑问的就是Login Server与Client的连接保持逻辑。当Client与Game Server连接了之后,Client并未与Login Server断开,是一直保持连接的。后来,经进一步的抓包分析,Client之所以要与Login Server保持这样的连接,是为了当Client重新选择服务器时,不至于重新连接Login Server。当Client点击了"选择服务器"按纽后,Login Server会每隔5秒向Client发一个当前所有的服务器列表数据包。要知道,这个服务器列表数据包的内容可是非常大的,如果有玩家就打开了这个窗口 不关闭,Login Server向这种情况的所有玩家每5秒钟就发一个服务器列表数据包,这个广播量可是很大的哦(2k左右,这可是一个用户是2k哦)。偶认为这里的逻辑设 计是相当不合理的。Login Server如果为了给客户端提供一个最新的全局服务器列表,可以保持连接,但也没必要每隔5秒就向客户端发一个服务器列表,最多只在客户端在某个服务器 上创建了不同的角色后再更新这个列表也是可以的,但只用更新这个列表中的变化内容即可,不用发全部的完整包,这样,在通信量上就小了很多。据说,魔兽刚开 始的时候,产生DOWN机的原因就是登录模块没有处理好,偶不知道现在的这个情况是不是已经经过改良的了。但偶还是认为每隔5秒就向客户端发送一个2K的 包,这一点是不可以被接受的。

  以上只是针对于魔兽世界登录流程的简单分析,没有多少技术含量,拿出来跟大家相互讨论讨论,看看有没有可以借鉴的地方,后面还会有其它部分的封包分析。欢迎继续关注偶的Blog: http://blog.csdn.net/sodme

  偶在文章前面部分说过,作为一个网络编程人员,熟练使用截包软件和掌握基本的封包分析方法是其基本能力之一,发此文的目的一个原因也是希望向正在作网络编程的兄弟介绍一下相关工具的使用和常见的分析方法。下面补充一下关于封包分析的基本方法和相关工具:

  1.你需要一个截包工具,偶推荐:commview,小巧但功能强大,支持自定义的封包分析插件以DLL形式装载,也就是说只要你愿意,你可以写个DLL对某类特殊形式的包进行显示、记录、解密等特别处理。

2.如何查看真正的封包数据。在commview里,会详细列出自网卡级别以上的各层封包数据,包括Ethernet层,IP层和TCP层。而我们作封 包分析时,只需要关注TCP层。但TCP层里也有很多内容,对于我们的分析需求来说,我们需要关注的是其Data字段(在协议目录里可以看到"data length标识,点击即可查看data段")的内容。

  3.TCP的几个状态对于我们分析所起的作用。在TCP层,有个FLAGS字 段,这个字段有以下几个标识:SYN, FIN, ACK, PSH, RST, URG.其中,对于我们日常的分析有用的就是前面的五个字段。它们的含义是:SYN表示建立连接,FIN表示关闭连接,ACK表示响应,PSH表示有 DATA数据传输,RST表示连接重置。其中,ACK是可能与SYN,FIN等同时使用的,比如SYN和ACK可能同时为1,它表示的就是建立连接之后的 响应,如果只是单个的一个SYN,它表示的只是建立连接。TCP的几次握手就是通过这样的ACK表现出来的。但SYN与FIN是不会同时为1的,因为前者 表示的是建立连接,而后者表示的是断开连接。RST一般是在FIN之后才会出现为1的情况,表示的是连接重置。一般地,当出现FIN包或RST包时,我们 便认为客户端与服务器端断开了连接;而当出现SYN和SYN+ACK包时,我们认为客户端与服务器建立了一个连接。PSH为1的情况,一般只出现在 DATA内容不为0的包中,也就是说PSH为1表示的是有真正的TCP数据包内容被传递。TCP的连接建立和连接关闭,都是通过请求-响应的模式完成的。


  封包分析的手段,说简单也挺简单的,那就是:比较!要不断地从不同的思维角度对封包进行对比分析,要充分发挥你的想象力不断地截取自己需要的包进行比较。不仅要作横向(同类)的比较,还要作纵向(不同类)的比较。即时对于同一个包,也要不断地反复研究。

  初涉封包分析的新手,一般会不知道封包分析究竟该从何入手。基于经验,本文将告诉你一般会从哪些类型的包入手进行分析以及应该怎样对封包进行初 步的分析。需要指出的是:封包分析是一件非常有趣但同时也非常考验耐心的事,通常,半天的封包分析下来,会让你眼前全是诸如“B0 EF 58 02 10 72....”之类的网络数据,而且附带有头疼、头晕症状,所以,没有充分的心理准备,还请不要轻易尝试。呵呵。

  从事封包分析的基本前提是:应该了解和熟悉TCP协议,并知道数据包“粘合”是怎么一回事。当然,我们平常截获到的包,从数量上来看,只有一小 部分是属于“粘合”的情况。但如果不了解它,将可能会对你的分析思路产生误导和困惑。关于“粘包”的更详细解释,请参考我的另外一篇文章“拼包函数及网络 封包的异常处理(含代码) (http://blog.csdn.net/sodme/archive/2005/07/10/419233.aspx)”。

  上一篇有关魔兽世界封包分析的文章(http://blog.csdn.net/sodme/archive/2005/06/18/397371.aspx)中,我根据客户端与服务器端连接及断开事件的处理流程以及登录过程中的一些数据包分析了魔兽的架构和登录逻辑。这篇文章中,我将结合聊天数据包的分析,来阐述魔兽世界封包的大体结构。  

  首先解释一下我们的目标:封包的大体结构。封包的大体结构包含哪些内容呢?一般情况下,封包的大体结构至少包括两方面的信息:
  1、一个封包是如何表示它的长度的?封包长度是由哪个字段表示的?(或者说:如何表示封包的开始和结束的)
  2、各种不同的封包类型是通过哪个字段表示的?

  是不是所有游戏的封包都必然会有表示“长度”信息的“字段”呢?答案是否定的。有的游戏确实没有采用这种方式,它们的作法设定特殊的包开始和包 结束标志。但是,从应用的角度来看,偶推荐使用“长度”这样的方法,因为不管在网络底层的处理效率以及上层应用的处理便捷性来说,使用“长度”字段标识一 个完整的逻辑包都是比较好的办法。在确定了封包的大体结构后,我们才方便分析具体类型包(比如聊天、行走等)的详细结构。

  作数据包分析,在单纯采用黑箱分析的阶段,我们选取的数据包,须要是具有这种性质的,即:在数据包发送前客户端未进行加密等处理时,这个数据包 中的部分内容,我们是已经知道的。这样的包,就可以作为封包分析的突破口。这样看来,我们拿“聊天封包”作为第一个分析对象也就不难理解了,因为我们说的 话,打上去的字,我们自己是知道的,但是我们说的话经过客户端的处理后,发到网络上的可能就是已经加了密的或者加了校验码的。站在黑箱分析的角度,我们能 作的,就是不断截取各种“聊天包”进行对比、判断和总结。

  OK,打开你的commview。让我们从“聊天封包”开始。

  分析“聊天包”的前提,是我们能够正常判断哪种类型的数据包是属于聊天的,不要误把行走或其它的数据包当作了聊天数据包。为了减小分析难度,建 议新手到游戏中人少或周围没有玩家的地方进行封包分析。这样一来没人打扰,二来你的网络通信量会相对小得多,比较容易进行一些封包判定。

  第一步,我们需要确定客户端与服务器通信所用的端口,然后在commview的rules->ports中设定服务器端口,截获与该端口 通信的所有数据包。服务器端口的确定方法:不要使用其它网络通信工具,打开commview,进游戏,截包,观察其通信端口。进行封包分析时,特别是初期 的封包分析时,你的网络通信应该尽可能是单一的,即:除了游戏,其它的通信软件尽可能不要开。但当你确定了服务器的IP和端口后,就可以照常使用其它网络 软件了。

  第二步,如前面述,在游戏中找个人少或没人的地方,开始“自言自语”,呵呵。说话的内容,建议以字母和数字为宜,不要说中文。因为中文是双字节 的,而字母和数字是单字节的,对于单字节的信息内容,截包软件会以单字节的文本信息显示,但对于双字节的汉字而言,截包软件在对其进行显示时由于换行等原 因会造成部分中文显示有乱码,不容易直接看出中文内容。如果执意要说中文,偶也不拦你,给你推荐一个工具:String Demander(下载地址:http://www.cnxhacker.com/Download/show/395.html),这个软件,可以查询中文所对应的编码。

  第三步,设定好commview的rules并使之生效,开始截包。

  观察通过以上的过程所截的包,可以发现,魔兽世界的聊天封包的说话内容是明文的!这一点,用不着大惊小怪,呵呵。聊天封包本身并不会对游戏的关 键逻辑造成损害,所以,即使让其明文显示也不足为奇。但是,我们还是不太相信自己的眼睛,于是再截若干个包,发现包中的说话内容确实是明文的!但是,包的 其它字段却是我们一时看不懂的“密文”。

  看来,下面的事情就是对这些包里的“密文”进行研究了。一般情况下,这种“密文”的加密方法,通过封包分析是分析不出来的,但,我们仍然可以通过封包分析来推论一些与“密文”生成算法有关的问题。我们可以作以下的对比分析:
  1、连续三次输入“a”,并分别观察及保存封包数据;
  2、连续三次输入“aa”,并分别观察及保存封包数据;
  3、连续三次输入“aaa”,并分别观察及保存封包数据。

  输入的封包用例,我们选择了字母"a",它的ASCII码是61。输入的规律是:每种情况连续输入三次,然后逐次增加a字母的个数。于是,我们发现这样一个有趣的现象:
  1、包中有关说话的内容是明文的;
  2、即使针对于同样的说话内容,比如“a”,客户端所发出去的包也是不一样的;
  3、当一次说话的字母个数增加1时,封包的总体长度也随之增加1;
  4、除每个封包的前面6个字节以及说话的字节外,其余的封包内容每次都一样;
  5、每个聊天封包的结尾字节都是0。

  于是,我们可以试着得出如下结论:
  1、包是没有压缩的,它所使用的加密算法应该是按字节进行的,并没有改变封包的长度使之看上去使用统一的长度;
  2、包是以0结尾的(尽管我们不知道它是以什么表示开头的,呵呵);
3、封包加密算法中所使用的密钥是可变的,即针对于相同的数据包内容由于加密的密钥不同,所以产生的密文也不同。由于客户端的数据传到服务器端后,服务 器端还要对数据进行解密。所以,客户端的加密算法与服务器端的解密算法应该共用了前6字节中的某些内容,以此作为解密算法的密钥。如果这6字节中没有包含 有关封包加、解密所需要的同步数据,那客户端和服务器之间应该会通过其它的方式同步这样的数据。不过,偶倾向于前者,即:这6字节中应该含有加、解密所需 要的密钥信息。

  回头看我们上面观察到的有趣现象,针对于第2点,反过来想,这应该也是最起码的功能了。就是说,即使客户端作出的是同样的动作,在客户端发出的包中,包的内容也是不一样的。这样,外挂就不能靠单纯的重复发相同的包而达到其目的了。

  分析来分析去,我们还是没能确定魔兽封包的大体结构。其实,到现在,我觉得我此文的目的已经达到了,即向大家展示封包分析的思维角度和思维方 式。至于具体结果,偶觉得倒真的不重要的了。可以肯定地告诉大家的是,魔兽的封包结构偶大致已经掌握了。偶仅在此公布我的分析结果:
  1、魔兽的封包长度字段是每个封包的前两字节,它的表示方式是:前两字节的数值+2。之所以加这个2,是因为封包长度字段本身占用了两个字节的长度。
  2、魔兽的封包类型偶推断是第三和第四字节,其中普通聊天的类型标识是“95 00”。

  请不要来信向我询问任何有关魔兽封包破解的内容,偶能说的都已经在文章里说了,偶之所以写这个系列的文章不是想破解魔兽,而是想以这样优秀的一 款游戏作为案例来向大家展示它在封包设计方面值得我们学习和讨论的地方,同时向更多的朋友普及有关封包分析的常识、工具以及思维方式,仅此而已。

  ps:由于每次封包分析的内容都很多,所以,一有了点结论后,要及时记录和总结,并与之前取得的总结进行对比,及时更新相关的记录文档。

posted @ 2009-09-23 23:48 暗夜教父 阅读(774) | 评论 (0)编辑 收藏
本文作者:sodme
本文出处:http://blog.csdn.net/sodme
声明:本文可以不经作者同意任意转载,但任何对本文的引用都须注明作者、出处及此声明信息。谢谢!!

  在网络应用中,“负载均衡”已经不能算是什么新鲜话题了,从硬件到软件,也都有了很多的方法来实现负载均衡。我们这里讨论的负载均衡,并不是指依靠DNS转向或其它硬件设备等所作的负载均衡,而是指在应用层所作的负载均衡。

  一般而言,只有在大型在线系统当中才有必要引入负载均衡,那么,多大的系统才能被称为大型系统呢?比如动辄同时在线数十万的网络游戏,比如同时在线数在10万以上的WEB应用,这些我们都可以理解为大型系统,这本身就是一个宽泛的概念。

设计再好的服务器程序,其单个程序所能承载的同时访问量也是有限的,面对一个庞大且日益增长的网络用户群,如何让我们的架构能适应未来海量用户访问,这 自然就牵涉到了负载均衡问题。支持百万级以上的大型在线系统,它的架构核心就是如何将“百万”这么大的一个同时在线量分摊到每个单独的服务器程序上去。真 正的逻辑处理应该是在这最终的底层的服务器程序(如QQ游戏平台的游戏房间服务器)上的,而在此之前所存在的那些服务器,都可以被称为“引路者”,它们的 作用就是将客户端一步步引导到这最终的负责真正逻辑的底层服务器上去,我们计算“百万级在线”所需要的服务器数量,也是首先考虑这底层的逻辑服务器单个可 承载的客户端连接量。

  比如:按上篇我们所分析QQ游戏架构而言,假设每个服务器程序最高支持2W的用户在线(假设一台机子只运行一个 服务器程序),那么实现150万的在线量至少需要多少台服务器呢?如果算得简单一点的话,就应该是:150/2=75台。当然,这样算起来,可能并不能代 表真正的服务器数量,因为除了这底层的服务器外,还要包括登录/账号服务器以及大厅服务器。但是,由于登录/账号服务器和大厅服务器,它们与客户端的连接 都属于短连接(即:取得所需要信息后,客户端与服务器即断开连接),所以,客户端给这两类服务器带来的压力相比于长连接(即:客户端与服务器始终保持连 接)而言就要轻得多,它们的压力主要在处理瞬间的并发访问上。

  “短连接”,是实现应用层负载均衡的基本手段!!!如果客户端要始终与登录/账号服务器以及大厅服务器保持连接,那么这样作的分层架构将是无意义的,这也没有办法从根本上解决用户量不断增长与服务器数量有限之间的矛盾。

当然,短连接之所以可以被使用并能维护正常的游戏逻辑,是因为在玩家看不到的地方,服务器与服务器之间进行了大量的数据同步操作。如果一个玩家没有登录 到登录服务器上去而是直接连接进了游戏房间服务器并试图进行游戏,那么,由于游戏房间服务器与大厅服务器和登录/账号服务器之间都会有针对于玩家登录的逻 辑维护,游戏房间服务器会检测出来该玩家之前并没有到登录服务器进行必要的账号验证工作,它便会将玩家踢下线。由此看来,各服务器之间的数据同步,又是实 现负载均衡的又一必要条件了。

  服务器之间的数据同步问题,依据应用的不同,也会呈现不同的实现方案。比如,我们在处理玩家登录这个问 题上。我们首先可以向玩家开放一些默认的登录服务器(服务器的IP及PORT信息),当玩家连接到当前的登录服务器后,由该服务器首先判断自己同时连接的 玩家是不是超过了自定义的上限,如果是,由向与该服务器连接着的“登录服务器管理者”(一般是一个内部的服务器,不直接向玩家开放)申请仲裁,由“登录服 务器管理者”根据当前各登录服务器的负载情况选择一个新的服务器IP和PORT信息传给客户端,客户端收到这个IP和PORT信息之后重定向连接到这个新 的登录服务器上去,完成后续的登录验证过程。

  这种方案的一个特点是,在面向玩家的一侧,会提供一个外部访问接口,而在服务器集群的内部,会提供一个“服务器管理者”及时记录各登录服务器的负载情况以便客户端需要重定向时根据策略选择一个新的登录接口给客户端。

采用分布式结构的好处是可以有效分摊整个系统的压力,但是,不足点就是对于全局信息的索引将会变得比较困难,因为每个单独的底层逻辑服务器上都只是存放 了自己这一个服务器上的用户数据,它没有办法查找到其它服务器上的用户数据。解决这个问题,简单一点的作法,就是在集群内部,由一个中介者,提供一个全局 的玩家列表。这个全局列表,根据需要,可以直接放在“服务器管理者”上,也可以存放在数据库中。

  对于逻辑相对独立的应用,全局列表的 使用机会其实并不多,最主要的作用就是用来检测玩家是不是重复登录了。但如果有其它的某些应用,要使用这样的全局列表,就会使数据同步显得比较复杂。比 如,我们在超大无缝地图的MMORPG里,如果允许跨服操作(如跨服战斗、跨服交易等)的话,这时的数据同步将会变得异常复杂,也容易使处理逻辑出现不可 预测性。

  我认为,对于休闲平台而言,QQ游戏的架构已经是比较合理的,也可以称之为休闲平台的标准架构了。那么,MMORPG一般的架构是什么样的呢?

MMORPG一般是把整个游戏分成若干个游戏世界组,每个组内其实就是一个单独的游戏世界。而不同的组之间,其数据皆是相互独立的,并不象QQ休闲平台 一样所有的用户都会有一个集中的数据存放点,MMORPG的游戏数据是按服务器组的不同而各自存放的。玩家在登录QQ游戏时,QQ游戏相关的服务器会自动 为玩家的登录进行负载均衡,选择相对不忙的服务器为其执行用户验证并最终让用户选择进入哪一个游戏房间。但是,玩家在登录MMORPG时,却没有这样的自 动负载均衡,一般是由玩家人为地去选择要进入哪一个服务器组,之所以这样,是因为各服务器组之间的数据是不相通的。其实,细致想来,MMORPG的服务器 架构思想与休闲平台的架构思想有异曲同工之妙,MMORPG的思想是:可以为玩家无限地开独立的游戏世界(即服务器组),以满足大型玩家在线;而休闲平台 的思想则是:可以为玩家无限地开游戏房间以满足大量玩家在线。这两种应用,可以无限开的都是“具有完整游戏性的游戏世界”,对于MMORPG而言,它的一 个完整的游戏地图就是一个整体的“游戏世界”,而对于休闲平台,它的一个游戏房间就可以描述为一个“游戏世界”。如果MMORPG作成了休闲平台那样的全 服皆通,也不是不可以,但随之而来的,就是要解决众多跨服问题,比如:好友、组队、帮派等等的问题,所有在传统MMORPG里所定义的这些玩家组织形式的 规则可能都会因为“全服皆通”而改变。

  架构的选择是多样性的,确实没有一种可以称得上是最好的所谓的架构,适合于当前项目的,不一定就适合于另一个项目。针对于特定的应用,会灵活选用不同的架构。但有一点,是可以说的:不管你如何架构,你所要作的就是--要以尽可能简单的方案实现尽可能的稳定、高效!
posted @ 2009-09-23 23:48 暗夜教父 阅读(736) | 评论 (0)编辑 收藏
仅列出标题
共9页: 1 2 3 4 5 6 7 8 9 

<2024年7月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

常用链接

留言簿(2)

随笔分类

随笔档案

文章分类

文章档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜