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 ...
随机推荐
- 左连接、右连接、内连接和where
首先可以看下w3school写的关于join的介绍: http://www.w3school.com.cn/sql/sql_join.asp on是关联条件,where是筛选条件 数据库在通过连接两张 ...
- Android 电池关机充电
android 电池(一):锂电池基本原理篇 android 电池(二):android关机充电流程.充电画面显示 android 电池(三):android电池系统 android电池(四):电池 ...
- 002. MySQL复制操作
#### 1.Setting the Replication Master Configuration On a replication master, you must enable binary ...
- FTP vsftp 安装、管理
FTP简介 FTP是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为文传协议,用户Internet上的控制文件的双向传输. FTP的主要作用,就是让用户链接上一个远 ...
- c刷新缓冲区
int c; while((c = getchar()) != '\n' && c != EOF);
- os包方法
os包中实现了平台无关的接口,设计向Unix风格,但是错误处理是go风格,当os包使用时,如果失败之后返回错误类型而不是错误数量. os包中函数设计方式和Unix类似,下面来看一下. func Chd ...
- jsp——js事件修改属性样式的两种方法(直接赋值、修改属性)、验证表单符合某要求、阻止表单提交、告诉浏览器不要缓存
代码 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncodi ...
- 数字组合问题:Combination,CombinationSum,CombinationSum2,CombinationSum3
Combination问题描述:给定n和k,找出1-n之间所有k个数的组合,例如:n=3,k=2,返回 [[1,2] [1,3] [2,3]] 算法分析:利用递归.递归边界就是curr.size( ...
- istringstream 用法
istringstream 类用于执行C++风格的串流的输入操作 istringstream用空格作为字符串分隔符 #include <iostream>#include <sstr ...
- Android Studio混淆打包
1.apk混淆打包 如果要对apk进行混淆,你要先告知gradle这个app需要混淆,并告知其混淆规则. 告知gradle需要混淆的代码 在Project/app/build.gradle中把mini ...