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 ...
随机推荐
- HDU 6356 Glad You Came 2018 Multi-University Training Contest 5 (线段树)
题目中没有明说会爆int和longlong 的精度,但是在RNG函数中不用unsigned int 会报精度,导致队友debug了很久... 根据每次生成的l,r,v对区间更新m次,然后求 i*ai的 ...
- 使用sqoop把mysql数据导入hive
使用sqoop把mysql数据导入hive export HADOOP_COMMON_HOME=/hadoop export HADOOP_MAPRED_HOME=/hadoop cp /hive ...
- SqlHelper简单实现(通过Expression和反射)5.Lambda表达式解析类
这个ExpressionHelper类,是整个SqlHelper中,最核心的一个类,主要功能就是将Lambda表达式转换为Sql语句.同时这个转换过程比较复杂,所以下面详细讲解一下思路和这个类的作用. ...
- Spring Web MVC 随笔
1.ContextLoaderListener 对于使用Spring的Web应用,无需手动创建Spring容器,而是通过配置文件声明式地创建Spring容器.可以直接在web.xml文件中配置创建Sp ...
- myelcipse中SVN进行代码更新和提交
感谢博主(John的专栏)的奉献,http://blog.csdn.net/tangzenglei/article/details/50175639
- 入职第一个项目bug总结-2018/07/28
此项目是正式入职后的第一个项目,可能各种原因重重,导致测试提出了如此多的bug,关于那些因为需求不清楚而导致的就不说了,bug总结如下: 一.ElementUI table组件出现横向滚动条 原因:因 ...
- Java:执行jar文件命令
Java:执行jar文件命令 执行jar文件命令: java -jar test.jar win7系统切换目录命令: cd /d d:/test
- 20145109 《Java程序设计》第六周学习总结
Chapter 10 I/O 10.1 InputStream & OutputStream a new 'try' edition: try (InputStream input = src ...
- codeforces 808D
题意:给出一个序列,询问是否能移动一个数(或不操作)使得序列能分为左右两个和相等的子序列. 思路:对每个数处理最左边和最右边出现的位置.设置断点分左右区间,左右区间和差值的一半就是要找的数,进行判断. ...
- resultMap结果集映射
resultMap结果集是用来定义sql查询的结果与java对象的映射关系.它主要解决2大问题: 1)可以解决POJO属性名和表结构的字段名不一致问题(甚至是 不是标准的驼峰命名法) 2)可以完成高级 ...