星期六, 五月 5, 2012, 02:09 PM ( 12 次浏览 )
- -Ruby & Rails -
游戏服务器最近测试中,发现了一些不可重复的案例,会导致服务器端挂掉。挂掉可能有多种情况,可能是内存错误导致整个服务器程序崩溃,另外是某个服务器线程内部问题导致这个服务线程阻塞,无法向新用户提供服务,当然还有可能是其他的原因。对玩家来说,表象就是游戏服务器端没反应,游戏卡死了。在这种情况下,即使用户重新刷新游戏界面或重启游戏客户端,仍然无法继续进行游戏,需要让用户继续游戏就需要重新启动游戏服务器端。 在bug根源没找到的情况下,游戏服务器端需要做的一件事情应该是发现问题,迅速重启。解决的办法是:服务器端用Ruby脚本写一小段程序,模拟一个测试用客户端,向服务器监听端口发送游戏逻辑,看是否能在指定的时间间隔内得到响应,如果指定时间内没有响应,则认为服务器端有问题;通过系统命令找到服务器监听程序的进程ID,强制结束进程,然后重启服务器端。
实现过程中,采用Ruby TCPSocket链接服务器后,然后通过send和recv来发送和接收数据。默认情况下,recv是阻塞的,只有等到服务器端有数据返回后,程序才能继续执行下去。在本例中,存在的一个可能情况是连接和发送数据都没有问题,但没有数据返回,导致阻塞的recv一直阻塞。因此,在此例中如果使用非阻塞的Socket接收机制会更好(当然可以通过多线程的方式来使用阻塞Socket,但代码会稍微复杂些)。
Google和百度了一把,找到的可参考的不多,又参考了ruby-doc.org上的API文档,写了下面的代码来使用非阻塞的recv_nonblock,测试通过。放在这里供有同样需求的朋友参考,至于原理,自己思考吧 ^-^
….
send_data = “aaaaaaaaaaaaa”;
i = 0;
begin
t = TCPSocket.new("127.0.0.1", 80);
t.send(send_data, 0);
begin
recv_data = t.recv_nonblock(100); #也可用read_nonblock代替
recv_data.strip!;
rescue IO::WaitReadable
i = i + 1;
if i<max_delay #最大等待时间
sleep(1); # 等待1秒
#IO.select([t]); # 此行会导致recv_nonblock阻塞
retry;
end
end
t.close;
puts "Server is ok!";
rescue Errno::ECONNREFUSED
ph_ok = false;
puts "server not in listening!";
rescue Exception=>ex
puts ex.to_s;
end
0 引用
| 永久链接
|
| 







星期一, 三月 12, 2012, 12:39 AM ( 37 次浏览 )
- -FlyMyApp -
http://www.flymyapp.com域名申请下来了,先放在香港的空间上,省备案的麻烦;自己做了一个首页面,先挂起来了,一方面是收集有兴趣参与内测的用户,另一方面是让搜索引擎能慢慢检索到。 欢迎有兴趣的同学提交邮件地址,可以内测后,必定会发内测帐号给你,早测早享受,哈哈!目前开发的阶段是:已经实现了一些基本的应用(可以是Flash、IOS、Android、HTML应用)关心的统计分布和趋势,包括但不限于:
1> 在线用户:
a> 最近在线用户趋势,可以分为最近2、4、6、12、24小时内;
b> 历史在线用户趋势,可以查看任意的历史天的和任意历史时间天数内的在线用户趋势图,同时提供快捷选择;
2> 活跃用户:
a> 最近活跃用户趋势,可以分为最近1、2、4、6、12、24小时内;
b> 历史活跃用户趋势,可以查看任意的历史天的和任意历史时间天数内的活跃用户趋势图,同时提供快捷选择;
3> 用户地域:
a> 今日地域分布:当天零时开始的来自全球不同国家用户的分布比例图和具体用户数对比图,同时提供来自中国不同省份的用户的分布比例图和具体用户数对比图;
b> 历史地域分布:历史任意时间段的全球不同国家和中国不同身份用户的比例和具体对比;
4> 登入时间段:任意时间天数内用户在24小时时间段(小时分割)的用户开始使用应用的人数;
5> 使用时长:任意时间天数内每次使用使用的不同时间长度的用户数分布;
6> 功能使用:
a> 任一应用可以单独定义需要统计的每项功能;
b> 功能在任一天或任一历史时间段内的用户使用次数和平均使用时长的分布;
7> 停留时间:
a> 应用可自定义需要统计的指定停留时间(某界面或某两个功能之间等);
b> 任意历史时间段内的用户停留时间的分布和趋势;
8> 转换率:
a> 应用可自定义需要统计的任意两个点之间的转换率;
b> 任意历史时间段内的转换率分布和趋势;

星期一, 二月 20, 2012, 12:35 AM ( 44 次浏览 )
- -Ruby & Rails -
笔者碰到的问题是这样的:Rails中生成了一系列的二维数组,比如@r_ary = [[0,”a”],[1,”b”],[2,”c”]]],需要直接在网页的Javascript代码中使用这个数组,大概代码如下:<script type="text/javascript">
… …
var a_ary = <%= @r_ary %>
… …
</script>在浏览器里运行,并没有得到想要的结果;在IE8中,输出了产生了这样的错误: “消息: 由于出现错误 80020101 而导致此项操作无法完成”。笔者尝试用alert输出结果,显示的结果也没有问题;有点百思不得其解。
Google一把后,得到的一个启示是转换为JSON数据格式,这样是否可行呢?将上述中间行代码改为:
var a_ary = <%= @r_ary.to_json %>结果令人失望,还是不行。
后来在查看浏览器重服务器端获取的源码时才发现,Rails在渲染网页代码时,自动进行了html编码,将双引号转变为了”"”,这样原来的数组变成了[[0,"a"],[1, "b"],[3, "c"]],显然这不是我想要的结果,也就导致在JS处理中出错了,得不到想要的结果。
找到了原因,问题就容易解决了,解决的思路就是让Rails不要对此变量的值进行html编码;自然联想到的方法是html_safe。直接在数据后面试了一下,如下:
var a_ary = <%= @r_ary.html_safe %>服务器端报错,没有这个方法;再尝试了一下先转换为JSON数据格式,再使用这个方法,如下:
var a_ary = <%= @r_ary.to_json.html_safe %>这下可以了,得到了想要的结果。 ^_^
星期五, 二月 17, 2012, 10:07 PM ( 64 次浏览 )
- -Ruby & Rails -
笔者前面有介绍过如何在通过配置database.yml文件让model能连接不同的数据库,那么如果是在controller的代码中需要动态连接非默认数据该怎么做呢?通常默认数据库的连接可以通过如下方式得到:
default_db_connection = ActiveRecord::Base.connection笔者通过摸索,得到两种解决办法(并未从原理上做很深的探究,所以不保证在任何情况下都可行, ^-^):
方法一:临时改变默认的数据库连接,用完再改回来;比如我们需要连接database.yml定义的new_db_development数据库(假设默认的是development),则可以用如下代码:
config = YAML::load(File.open('config/database.yml'))
ActiveRecord::Base.establish_connection(config["new_db_development"])
…. #your code here
ActiveRecord::Base.establish_connection(config["development"])方法二:受model连接非默认数据库方式的启发,可以利用一个空白定义的model来得到数据库连接connection,过程如下:
1.首先创建一个空白的model,手动编写一个即可,更方便;在app/model文件夹下创建new_db.rb文件,填入如下内容:
class NewDb < ActiveRecord::Base
establish_connection :new_db_development
end2.在controller代码中,获得到new_db_development定义的数据库的连接实例:
new_db_connection = NewDb.connection;3.然后在后续代码中即可通过new_db_connection执行对非默认数据库的操作。
方法二相比方法一的好处是,同时拥有对默认数据库和非默认数据库的连接实例,方便处理。
星期四, 二月 16, 2012, 08:35 PM ( 39 次浏览 )
- -Ruby & Rails -
在设计一个可能需要创建大规模用户,并且用户会有很多自定义数据系统的数据库时,为了提高数据库访问的性能,并且易于管理,需要在程序中动态创建数据表,并且同时需要创建用于映射此数据表的model,如何在Rails Web应用的controller中实现呢?参考http://stackoverflow.com/questions/4673 ... e-in-rails 后,笔者实现了如下函数:def create_new_table(schema_name, table_name)
begin
ActiveRecord::Schema.define do
create_table "#{schema_name}.#{table_name}" do | t |
t.integer :aaaa_id, :null=>false
t.string :aaaa_name, :null=>false, :default=>0
t.datetime :rec_time, :null=>false, :default=>'2012/2/14 00:00:00'
end
end
model_file = File.join("app", "models", table_name.singularize+".rb");
model_name = table_name.singularize.camelize;
File.open(model_file, "w+") do |f|
f << "class #{model_name} < ActiveRecord::Base\nend";
end
return true
rescue Exception => err
return err.message
end
end如果在某个逻辑处理时候,需要在数据库模式new_db中动态创建表 user_10000_tables,并且同时创建好对应的model,则只需调用上述函数,将数据库和表名作为参数传入,在此处例子中的调用方式如下:
create_new_table “new_db” “user_10000_tables” 如果数据库适配器的配置没有问题,则执行完后,将会在数据库模式new_db中创建好user_10000_tables数据表,同时在app/models/目录下生成user_10000_table.rb文件,文件的内容如下:
class User10000Table < ActiveRecord::Base
establish_connection :new_db_connection
end在以后的代码逻辑中就可以通过 User10000Table来使用new_db.user_10000_tables了。
[2012/2/17 Update: 修改增加连接多数据库]
上述代码显然只能在默认的数据库中创建表,如果需要动态地在非默认的数据库中创建表,该如何做呢?笔者研究出了两种看似可行的方法,参考笔者的“Rails Controller中动态连接非默认数据库”文章,这里采用第二种方法,修改后的代码如下:
def create_new_table(schema_name, table_name)
begin
ActiveRecord::Schema.define do
@connection = NewDB.connection;
create_table "#{schema_name}.#{table_name}" do | t |
t.integer :aaaa_id, :null=>false
t.integer :aaaa_name, :null=>false, :default=>0
t.datetime :rec_time, :null=>false, :default=>'2012/2/14 00:00:00'
end
end
model_file = File.join("app", "models", table_name.singularize+".rb");
model_name = table_name.singularize.camelize;
File.open(model_file, "w+") do |f|
f << "class #{model_name} < ActiveRecord::Base\n\testablish_connection :new_db_connection\nend";
end
return true
rescue Exception => err
return err.message
end
end上述代码中,假设new_db_connection已经在database.yml中定义好,并且NewDb model也创建好,并可用。如何定义并使用多数据库连接,可以参考本博客前一篇文章:Rails中连接多数据库
星期二, 二月 14, 2012, 05:32 PM ( 59 次浏览 )
- -Ruby & Rails -
在考虑Rails如何同时使用多个数据库时,找到这篇文章: http://pullmonkey.com/2008/4/21/ruby-on ... nnections/,挺不错的,顺手翻译一下:【翻译:】
在rails论坛回答问题时,看到了多数据库连接的需求。
需求是:我们需要在一个rails实例中使用两个数据库,更直接点就是我们需要同时使用Oracle和Mysql数据库。怎么做呢?首先,我们需要选择决定哪个数据库是我们的默认数据库,在本场景中,我选择Mysql,那么在database.yml文件中,会有如下配置:
# in your database.yml file
development:
adapter: mysql
username: root
password:
database: example_development这个相信是大家都比较熟悉的,此时我们的Active Record Models将会使用此mysql连接。
但是,我们同时又需要使用Oracle数据库,因此database.ym配置将会是这样的:
# in your database.yml file
development:
adapter: mysql
username: root
password:
database: example_development
oracle_development:
adapter: oracle
username: root
password:
database: example_oracle_development到此为止,我们有了两个用于开发的数据库连接,因此,我们需要告诉哪个models使用哪个连接。实际上,我们只需要告诉oracle models去连接oracle_development,所有其他的models连接默认的development。假设,有一个名为user的model,此model对应的数据表是存储在oracle数据库中,user model文件默认是如下样子的:
#RAILSROOT/app/models/user.rb
class User < ActiveRecord::Base
end 增加如下一行即可让此model连接配置的oracle_development连接:
establish_connection :oracle_development如何让此配置更加灵活呢?这样我们在test和production环境中,都不需要改变establish_connection行,比如这样:
# use RAILS_ENV where RAILS_ENV is generally development, test or production
establish_connection "oracle_#{RAILS_ENV}" 为了达到这个目的,相应的database.yml文件配置如下:
dev_basics: &dev_basics
username: root
password:
<% %w(development test production).each do |env| %>
<%= env %>:
<<: *dev_basics
adapter: mysql
database: example_<%= env %>
oracle_<%= env %>:
<<: *dev_basics
adapter: oracle
database: example_oracle_<%= env %>
<% end %> 即可!
【2012/2/16 Update】在database.yml新增适配器后,需要重启rails server,否则会出现找不到适配器错误!笔者为此Google了半天.... 汗啊....
星期二, 二月 14, 2012, 01:27 AM ( 38 次浏览 )
- -Ruby & Rails -
测试新浪微游戏接口时,发现一个问题:当使用IE浏览器的时候,rails的session无法保存。之前在自己开发服务器上测试时,验证过IE和Firefox都能正常使用session的,觉得很是奇怪。通过抓包发现,正常情况下,服务器端在响应客户端访问请求后,在返回的http头中会有Set-Cookies这样的参数,同时在接下来的客户端的http请求头中,会加上Cookie这样的参数;上述不能正常保存session情况下的抓包分析发现,客户端的http请求头中浏览器没有设置Cookie参数。
解决方法一:修改IE的默认Cookie设置,设置IE隐私设置中的高级隐私设置,勾选“总是允许回话Cookie”,这样session的值就能正常保存了。不过这样肯定不是最好的解决办法,对大多数用户来说,这样做不合理。
解决方法二:参考方法来自: http://www.sympact.net/2008/07/rails-and-ifram.html ,文中描述了具体原因,是因为IFrame中打开的链接和主页面的链接不在同一个域,所以IE默认会认为是不可信任的,则不允许使用Cookie。解决办法正如文中所示,在controller中的before_filter中增加一个方法,此方法中设置响应的http相应头中增加P3P参数,问题即可解决。
大致代码如下:
class ApplicationController < ActionController::Base
before_filter :set_response
protect_from_forgery
def set_response
response.headers['P3P'] = 'CP="CAO PSA OUR"'
end
end星期六, 一月 14, 2012, 08:38 PM ( 287 次浏览 )
- -旅游&摄影 -
前一段时间,参加了点名时间的谷岳( 博客 微博 )南美之旅的点名活动: http://demohour.com/projects/297196 , 今天收到了古岳从南美寄过来的明信片,挺开心的!
谷岳 -- 一个能追随自己梦想的人,永远支持你!





