ranch实现游戏服务器
在 erlang游戏开发tcp 我们建立起了自己的socket tcp 服务器的基本骨架。当时面对并发情况下,多人同一时刻连接服务器的时候,我们的基本骨架 还是难以应付处理。这就使我不得不想对这样的情况如何去处理。怎么处理呢? 预先开多个线程侦听连接,侦听到有连接后重新开线程处理当前连接,然后继续侦听连接。当然要自己处理这样的事情,也花费不到多少的时间。但是要弄成成熟稳定的骨架估计还是要花费一段时间的。本着不重复造轮子的原则。在这里我找到了大名鼎鼎cowboy使用的ranch。 它已经相当完美帮我实现了我前面所说的功能,并且经过大量的考验。下面我们就使用ranch 还实现我们的tcp 游戏服务器。
ranch的使用模式分为两种:第一种独立运行模式;第二种嵌入模式。 cowboy使用的独立运行模式,程序自带的例子也是独立模式运行。在这里我要做的是在ranch嵌入到我们的游戏服务器中,作为我们游戏的一部分运行,在同一监督树下工作。
整个实现过程在 erlang游戏开发tcp 基础上改造完成。
1.在rebar.config 中添加对应的依赖项
{deps, [
{ranch, ".*", {git, "https://github.com/extend/ranch.git", "master"}}
]}.
2.game_socket_app.erl修改为
-module(game_socket_app). -behaviour(application). %% Application callbacks
-export([start/, stop/]). -define(PORT,).
-define(LISTEMNUM,). %% ===================================================================
%% Application callbacks
%% =================================================================== start(_StartType, _StartArgs) ->
%%读取启动端口
Port = case application:get_env(game_socket, port) of
{ok, P} -> P;
undefined -> ?PORT
end,
%%侦听线程的个数
ListenNum = case application:get_env(game_socket,listemnum) of
{ok,L}->L;
undefined->?LISTEMNUM
end,
ok = game_socket_store:init(),
%%启动监督树
case game_socket_sup:start_link([Port,ListenNum]) of
{ok, Pid} ->
{ok, Pid};
Other ->
{error, Other}
end. stop(_State) ->
ok.
3.修改game_socket_sup.erl监督树
-module(game_socket_sup). -behaviour(supervisor).
-define(CHILD(I, Type,Parms), {I, {I, start_link,Parms}, permanent, , Type, [I]}).
%% ===================================================================
%% API functions
%% ===================================================================
%% API.
-export([start_link/]). %% supervisor.
-export([init/]). %% API.
start_link([Port,ListenNum]) ->
supervisor:start_link({local, ?MODULE}, ?MODULE, [Port,ListenNum]).
%--------------------------------------------------------------------
%% @doc init
%% @spec
%% @end
%%-------------------------------------------------------------------- init([Port,ListenNum]) ->
%%启动ranch监督树
RanchSpec=?CHILD(ranch_sup,supervisor,[]),
ListenerSpec = ranch:child_spec(game_socket_server,ListenNum,ranch_tcp, [{port, Port}], game_socket_server, []),
Childs=[RanchSpec,ListenerSpec],
{ok, {{one_for_one, , }, Childs}}.
4改造game_socket_server.erl
-module(game_socket_server).
-behaviour(gen_server).
-behaviour(ranch_protocol). %% API.
-export([start_link/]). %% gen_server.
-export([init/, handle_call/, handle_cast/, handle_info/,
terminate/, code_change/]). -define(TIMEOUT, ). -define(SERVER, ?MODULE). -record(state, {ref,socket, transport,otp,ip,port}). %% API. start_link(Ref, Socket, Transport, Opts) ->
gen_server:start_link(?MODULE, [Ref, Socket, Transport, Opts], []). %% gen_server. %% This function is never called. We only define it so that
%% we can use the -behaviour(gen_server) attribute. init([Ref, Socket, Transport,Opts]) ->
%%peername(Socket) -> {ok, {Address, Port}} | {error, posix()}
timer:send_interval(,timertick),
{ok,{Address,Port}} = inet:peername(Socket),
{ok, {state, Ref, Socket, Transport,Opts,Address,Port}, }.
%% timout function set opt parms
handle_info(timeout, State=#state{ref=Ref, socket=Socket, transport=Transport}) ->
ok = ranch:accept_ack(Ref),
ok = Transport:setopts(Socket, [{active, once}]),
game_socket_store:insert(self(),Socket),
{noreply, State};
%% handle socket data
handle_info({tcp, Socket, Data}, State=#state{socket=Socket, transport=Transport}) ->
Transport:setopts(Socket, [{active, once}]),
io:format("~p~n",[Data]),
lists:foreach(fun(Pid) ->
case Pid =:= self() of
false ->
gen_server:cast(Pid,{chat,Data});
true -> ok
end
end,
game_socket_store:lookall()),
{noreply, State, ?TIMEOUT};
handle_info(timertick,State=#state{socket=Socket,transport=Transport})->
Transport:send(Socket,<<>>),
{noreply,State}; handle_info({tcp_closed, _Socket}, State) ->
{stop, normal, State};
handle_info({tcp_error, _, Reason}, State) ->
{stop, Reason, State};
handle_info(timeout, State) ->
{stop, normal, State};
handle_info(_Info, State) ->
{stop, normal, State}. handle_call(_Request, _From, State) ->
io:format("handle_call message ~p ~n",[_Request]),
{reply, ok, State}. handle_cast({chat,Msg}, State=#state{socket=Socket, transport=Transport}) ->
Transport:send(Socket,Msg),
io:format("handle_cast message ~p ~n",[Msg]),
{noreply, State}. terminate(_Reason, _State) ->
game_socket_store:delete(self()),
ok. code_change(_OldVsn, State, _Extra) ->
{ok, State}.
经过以上4部我们初步的socket服务器搞定。怎么样感觉简单吧
最后 rebar g-d ./start-dev.sh appmon:start().去看看监督树吧。然后在添加几个连接看看监督树。
ranch实现游戏服务器的更多相关文章
- flash游戏服务器安全策略
在网页游戏开发中,绝大多数即时通信游戏采用flash+socket 模式来作为消息数据传递.在开发过程中大多数开发者在开发过程中本地没有问题,但是一旦部署到了网络,就存在连接上socket服务器.究 ...
- 游戏服务器菜鸟之C#初探一游戏服务
本人80后程序猿一枚,原来搞过C++/Java/C#,因为工作原因最后选择一直从事C#开发,因为读书时候对游戏一直比较感兴趣,机缘巧合公司做一个手游的项目,我就开始游戏服务器的折腾之旅. 游戏的构架是 ...
- 游戏服务器菜鸟之C#初探四游戏服务
经过多次折腾之后,在一次进行了一次重大的重构,去解决问题 主要重构如下 1.将原来的单一协议修改多协议进行,一些查询.认证的功能都采用HTTP进行,避免全部采用TCP链接资源的消耗: 2.原来单一的部 ...
- Redis在游戏服务器中的应用
排行榜游戏服务器中涉及到很多排行信息,比如玩家等级排名.金钱排名.战斗力排名等.一般情况下仅需要取排名的前N名就可以了,这时可以利用数据库的排序功能,或者自己维护一个元素数量有限的top集合.但是有时 ...
- c++游戏服务器编程学习笔记(一)TCP/IP
1. c++游戏服务器编程c++运行效率非常高2. TCP传输控制协议IP网际协议Socket 3.Linux 乌班图开源第三方库BOOST 4.80%游戏服务器端用C++工作量最大的地方是具体的游戏 ...
- 游戏服务器ID生成器组件
游戏服务器程序中,经常需要生成全局的唯一ID号,这个功能很常用,本文将介绍一种通用ID生成组件.游戏服务器程序中使用此组件的场景有: 创建角色时,为其分配唯一ID 创建物品时,每个物品需要唯一ID 创 ...
- 游戏服务器生成全局唯一ID的几种方法
在服务器系统开发时,为了适应数据大并发的请求,我们往往需要对数据进行异步存储,特别是在做分布式系统时,这个时候就不能等待插入数据库返回了取自动id了,而是需要在插入数据库之前生成一个全局的唯一id,使 ...
- Centos环境下部署游戏服务器-常用命令
图1 在Linux的世界,如果你不玩命令,那你见了同行都不好意思和人家打招呼.同时服务器正常状况下放在远端,一般都是开ssh登录服务器,相信远程桌面的人很少见吧.这篇文章说说Linu ...
- Centos环境下部署游戏服务器-编译
游戏服务器是在windows环境开发的,相关跨平台的东西在这里不谈了,只谈如何将Visual Studio 工程转换到Linux下编译.这里涉及到的软件分别为:Centos版本为6.4,Visual ...
随机推荐
- Hbase 布隆过滤器BloomFilter介绍
转载自:http://blog.csdn.net/opensure/article/details/46453681 1.主要功能 提高随机读的性能 2.存储开销 bloom filter的数据存在S ...
- Linux系统服务管理 服务管理
Linux独立服务管理 启动服务 systemctl start 服务名称.service 设置开机自启动 systemctl enable 服务名称.service 停止开机自启动 systemct ...
- Entity FrameWork Code First 迁移命令详解
1. Enable-Migrations 启动迁移 执行get-help Enable-Migrations –detailed 查看Enable-Migrations的详细用法. -ContextT ...
- JavaScript的消息机制
JavaScript本身是单线程的,但它却是事件驱动的.类似Windows窗体应用程序,它也需要消息队列机制来实现.程序的执行并不是连续的,绝大多数时间都在等待消息.每次执行执行程序都是在响应消息,这 ...
- 单元测试框架unittest,ddt
unittest case.py 测试用例 suite.py 测试套件 loader.py 加载测试用例 run.py 执行测试用例 result.py 测试结果,测试报告 main mock 模拟测 ...
- NEVER QUIT. NEVER SAY NEVER.
有志者不是从不失败,而是从不妥协. NEVER QUIT. NEVER SAY NEVER. 2015/09/15 Winners are not those who never fail but t ...
- redis通过命令批量删除key
需求:想删除 notify_ 开头的所有key redis-cli KEYS "notify_*" | xargs redis-cli DEL 通过 notify_* 来匹配
- springBean参数注入的几个方法
1.普通方式注入 applicationContext.xml <?xml version="1.0" encoding="UTF-8"?> < ...
- Mac Item2 SSH免密登录Linux 服务器的两种方式
转自http://blog.csdn.net/jobschen/article/details/52823980 mac ssh登录linux服务器 的两种方式: 个人推荐第二种,zsh方式,只需要把 ...
- Win7.还原默认打开方式
1.win7还原默认打开方式_百度知道.html(https://zhidao.baidu.com/question/1668708948433912307.html) Windows7:[47]打开 ...