在 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实现游戏服务器的更多相关文章

  1. flash游戏服务器安全策略

     在网页游戏开发中,绝大多数即时通信游戏采用flash+socket 模式来作为消息数据传递.在开发过程中大多数开发者在开发过程中本地没有问题,但是一旦部署到了网络,就存在连接上socket服务器.究 ...

  2. 游戏服务器菜鸟之C#初探一游戏服务

    本人80后程序猿一枚,原来搞过C++/Java/C#,因为工作原因最后选择一直从事C#开发,因为读书时候对游戏一直比较感兴趣,机缘巧合公司做一个手游的项目,我就开始游戏服务器的折腾之旅. 游戏的构架是 ...

  3. 游戏服务器菜鸟之C#初探四游戏服务

    经过多次折腾之后,在一次进行了一次重大的重构,去解决问题 主要重构如下 1.将原来的单一协议修改多协议进行,一些查询.认证的功能都采用HTTP进行,避免全部采用TCP链接资源的消耗: 2.原来单一的部 ...

  4. Redis在游戏服务器中的应用

    排行榜游戏服务器中涉及到很多排行信息,比如玩家等级排名.金钱排名.战斗力排名等.一般情况下仅需要取排名的前N名就可以了,这时可以利用数据库的排序功能,或者自己维护一个元素数量有限的top集合.但是有时 ...

  5. c++游戏服务器编程学习笔记(一)TCP/IP

    1. c++游戏服务器编程c++运行效率非常高2. TCP传输控制协议IP网际协议Socket 3.Linux 乌班图开源第三方库BOOST 4.80%游戏服务器端用C++工作量最大的地方是具体的游戏 ...

  6. 游戏服务器ID生成器组件

    游戏服务器程序中,经常需要生成全局的唯一ID号,这个功能很常用,本文将介绍一种通用ID生成组件.游戏服务器程序中使用此组件的场景有: 创建角色时,为其分配唯一ID 创建物品时,每个物品需要唯一ID 创 ...

  7. 游戏服务器生成全局唯一ID的几种方法

    在服务器系统开发时,为了适应数据大并发的请求,我们往往需要对数据进行异步存储,特别是在做分布式系统时,这个时候就不能等待插入数据库返回了取自动id了,而是需要在插入数据库之前生成一个全局的唯一id,使 ...

  8. Centos环境下部署游戏服务器-常用命令

         图1     在Linux的世界,如果你不玩命令,那你见了同行都不好意思和人家打招呼.同时服务器正常状况下放在远端,一般都是开ssh登录服务器,相信远程桌面的人很少见吧.这篇文章说说Linu ...

  9. Centos环境下部署游戏服务器-编译

    游戏服务器是在windows环境开发的,相关跨平台的东西在这里不谈了,只谈如何将Visual Studio 工程转换到Linux下编译.这里涉及到的软件分别为:Centos版本为6.4,Visual ...

随机推荐

  1. C# 中与等于 &= 操作符

    MSDN说,x&=y等价于 x=x&y. 整型时&运算符,进行位运算. bool类型时,&运算符,当两边结果都为ture时,结果才为true.

  2. xaml可扩展应用程序标记语言

    xaml 类似于 html,但不是html,它是基于xml语言的:’html可以呈现在浏览器中而xaml 可以现实 3d动画等特效. xaml  是强类型语言,  是解释性语言,虽然他可以被编译.

  3. 在HI3531上移植和运行QT4.8.6

    在HI3531上移植和运行QT4.8.6 1.            前言: 近段有点时间,想把QT移植到HI3531上,在网上查找了很多资料,但都不是很全面,有些有问题也没有得到很好的体现. 2.  ...

  4. Android应用程序用真机调试步骤

    仅供参考: 1.开启调试模式     2.安装 Adb.exe 将platform-tools文件夹里面adb.exe AdbWinApi.dll AdbWinUsbApi.dll拷贝到tools   ...

  5. JSP Tomcat8.0运行连接池时发生异常【AbstractMethodError oracle.jdbc.driver.T4CConnection.isValid(I)Z】

    原创 2015年12月28日 11:38:01 2004 一.Tomcat8.0运行连接池时发生异常: AbstractMethodError oracle.jdbc.driver.T4CConnec ...

  6. netbeans等宽字体却不支持中文

    一直用netbeans,各方面都很满意,就是这字体十分不爽,如用等宽字体却不支持中文,百度了一下,找到了解决办法,贴出来,给需要的朋友. 01.找到自己java字体目录.我的目录是[C:\Progra ...

  7. 第二篇:Spark SQL Catalyst源码分析之SqlParser

    /** Spark SQL源码分析系列文章*/ Spark SQL的核心执行流程我们已经分析完毕,可以参见Spark SQL核心执行流程,下面我们来分析执行流程中各个核心组件的工作职责. 本文先从入口 ...

  8. Kruskal算法-最小生成树

    2017-07-26  10:32:07 writer:pprp Kruskal算法是根据边的加权值以递增的方式,一次找出加权值最低的边来建最小生成树:并且每次添加的边不能造成生成树有回路,直到找到N ...

  9. Android QRCodeReaderView 和Camera API冲突

    开发一款小功能,核心功能是二维码扫描,然后发送到远端服务器.App结构分为两个Activity,Activity A 负责二维码扫描,然后将参数存到本地,再启动Activity B,在Activity ...

  10. Sort Colors,颜色排序

    问题描述:Given an array with n objects colored red, white or blue, sort them so that objects of the same ...