Erlang简单并行服务器

(金庆的专栏)

Erlang并行服务器为每一个Tcp连接创建相应的连接进程,处理client数据。

參考 Erlang程序设计(第2版)
17.1.3 顺序和并行服务器

并行服务器的诀窍是:每当gen_tcp:accept收到一个新连接时就马上分裂一个新进程。

为每一个新套接字连接创建一个并行进程。

-module(gs_svr).
-author("jinqing").

-behaviour(gen_server).

%% API
-export([start_link/0]).

init([]) ->
    gs_listener:start_parallel(),
    {ok, #{}}.

gs_svr(GameServer gen_server)启动Tcp监听。并维护连接,如连接计数,发送广播。

start_parallel()创建监听端口,然后创建连接进程。

start_parallel() ->
    Port = server_csv:get_my_port(),
    lager:info("Starting game server on port ~p...", [Port]),
    {ok, ListenSocket} = gen_tcp:listen(Port,
        [binary, {packet, 4},
            {packet_size, 256 * 1024},  % limit packet size
            {reuseaddr, true},
            {nodelay, true},
            {backlog, 999999},
            {active, once}]),
    connection:spawn_connection(ListenSocket).

spawn_connection()创建连接进程。每接受一个连接就再创建一个新的连接进程。

-module(connection).
-author("jinqing").

%% API
-export([spawn_connection/1]).
-export([parallel_connect/1, loop/2]).

-spec spawn_connection(ListenSocket :: gen_tcp:socket()) -> pid().
spawn_connection(ListenSocket) ->
    spawn(fun() -> ?

MODULE:parallel_connect(ListenSocket) end).

-spec parallel_connect(ListenSocket :: gen_tcp:socket()) -> ok.
parallel_connect(ListenSocket) ->
    {ok, Socket} = gen_tcp:accept(ListenSocket),
    spawn_connection(ListenSocket),
    
    gs_svr:cast_connection_new(self()),
    ConnStat = conn_stat:new(),
    erlang:send_after(1000, self(), timer_sec),
    try ?MODULE:loop(Socket, ConnStat)
    catch
        Type:E -> lager:error("loop() ~p:~p. ~p",
            [Type, E, erlang:get_stacktrace()])
    end,
    gs_svr:cast_connection_ended(self()),
    ok.

-spec loop(Socket :: gen_tcp:socket(), ConnStat :: conn_stat:conn_stat()) -> any().
loop(Socket, ConnStat) ->
    receive
        {tcp, Socket, Bin} ->
            NewConnStat = rpc_handler:handle_bin(Socket, Bin, ConnStat),
            inet:setopts(Socket, [{active, once}]),
            NewConnStat2 = cutil_dos_checker:on_data(size(Bin), NewConnStat),
            ?MODULE:loop(Socket, NewConnStat2#{idle_sec=>0});
        {tcp_closed, Socket} ->
            save_on_end(ConnStat);
        {tcp_error, Socket, Reason} ->
            save_on_end(ConnStat);

{gs_to_connection, Msg} ->
            NewConnStat = handle_gs_msg(Msg, Socket, ConnStat),
            ?MODULE:loop(Socket, NewConnStat);

timer_sec ->
            case conn_timer:timer_sec(ConnStat) of
                {ok, NewConnStat} ->
                    erlang:send_after(1000, self(), timer_sec),
                    ?MODULE:loop(Socket, NewConnStat);
            end;
        Other ->
            lager:error("Unknown msg: ~p", [Other]),
            ?MODULE:loop(Socket, ConnStat)
    end.  % This is tail-recursive.

缺点是连接进程没有增加监控树。

gs_svr出错重新启动时,连接进程connection应该断开并退出。

Erlang简单并行server的更多相关文章

  1. Erlang简单并行服务器

    Erlang简单并行服务器(金庆的专栏)Erlang并行服务器为每个Tcp连接创建对应的连接进程,处理客户端数据.参考 Erlang程序设计(第2版)17.1.3 顺序和并行服务器并行服务器的诀窍是: ...

  2. Ubuntu下erlang连接SQL SERVER 2008

    erlang连接SQL Server使用ODBC方法,但在网络上还是缺少资料,自己折腾了2天才成功.现在特记录下来,以供大家借鉴. 基本思路是 erlang odbcserver + unixodbc ...

  3. 为什么我要选择erlang+go进行server架构(2)

    原创文章,转载请注明出处:server非业余研究http://blog.csdn.net/erlib 作者Sunface 为什么我要选择Erlang呢? 一.erlang特别适合中小团队创业: erl ...

  4. spring cloud 创建一个简单Eureka Server

    在Spring Cloud实现一个Eureka Server是一件非常简单的事情.下面我们来写一个Eureka Server DEMO. 编码 父项目pom.xml <?xml version= ...

  5. 使用HANA Web-based Development Workbench创建最简单的Server Side JavaScript

    服务器端的JavaScript, 看下wikipedia的介绍: https://en.wikipedia.org/wiki/JavaScript#Server-side_JavaScript Ser ...

  6. Tomcat是怎么工作的(2) -- 动手实现山寨版的简单Web Server

    本文先讲解一下Java web server都是怎么工作的.web server也叫HTTP server——顾名思义它是用HTTP协议和客户端交互的.客户端一般就是各种各样的浏览器了.相信所有朋友都 ...

  7. Slickflow.NET 开源工作流引擎快速入门之二: 简单并行分支流程代码编写示例

    前言:对于急切想了解引擎功能的开发人员,在下载版本后,就想尝试编写代码,完成一个流程的开发和测试.本文试图从一个最简单的并行分支流程来示例说明,如何快速了解引擎代码的编写. 版本:.NET Core2 ...

  8. 写一个最简单的 Server

    import java.net.*;import java.io.*;public class Server{ public static void main(String[] args) throw ...

  9. asp.net Socket的简单Web Server

    1.首先初始化socket,包含对端点以及对连接队列长度的初始化 IPAddress address = IPAddress.Loopback; IPEndPoint endPoint = ); So ...

随机推荐

  1. django 笔记16 文件上传笔记

    views.py文件 def upload_file(request): username = request.POST.get('username') fafafa = request.FILES. ...

  2. 8.变量内存CPU原理

    编译器先明确是什么类型,然后明确变量名,变量表管理所有的变量,不在变量表内部的变量不能引用.每个变量对应一整块内存 a+1所计算出来的值在寄存器中,只有变量可以被赋值,变量必须在内存里面 c语言内嵌汇 ...

  3. Kali linux 2016.2(Rolling)中metasploit的搜集特定地址的邮件地址

    不多说,直接上干货! 使用search_email_collector搜集特定地址的邮件地址 search_email_collector 要求提供一个邮箱后缀,通过多个搜索引擎的查询结果分析使用此后 ...

  4. spring boot自动配置之jdbc

    1.DataSource配置 1.1 默认配置application.xml spring.datasource.url=jdbc:mysql://localhost/test spring.data ...

  5. HikariCP--一款高性能的 JDBC 连接池

    源码地址:https://github.com/brettwooldridge/HikariCP 使用方法: Java 8 maven artifact: <dependency> < ...

  6. php文件加载、错误处理、方法函数和数组

    数组运算符注意:php中,数组的元素的顺序,不是由下标(键名)决定的,而是完全由加入的顺序来决定.联合(+):将右边的数组项合并到左边数组的后面,得到一个新数组.如有重复键,则结果以左边的为准$v1 ...

  7. NodeJS学习笔记 (28)流操作-stream(ok)

    模块概览 nodejs的核心模块,基本上都是stream的的实例,比如process.stdout.http.clientRequest. 对于大部分的nodejs开发者来说,平常并不会直接用到str ...

  8. UCOSii任务就绪表之OSUnMapTbl[16*16]的数组是如何得到的

    我比较喜欢图,如下图: 图1: INT8U const OSUnMapTbl[]数组内的数据. 1.UCOSii的优先级相关内容 首先先介绍一个概念:优先级.UCOSii的优先级按倒叙排列,即优先级数 ...

  9. echarts如何修改数据视图dataView中的样式

    原文链接:点我 做了一个现实折线图的图表,通过右上角icon可以自由切换成柱状图,表格.在表格中遇到的一点小问题,解决方案如下: 1.场景重现 这是一个显示两个折线图的图表,一切看起来都很顺利.但是点 ...

  10. JavaScript笔记(3)

    •位操作符 所有的按位操作符的操作数都会被转成补码形式的有符号的32位整数. 运算符 用法 描述 按位与(AND) a & b 对于每一个比特位,只有两个操作数相应的比特位都是1时,结果才为1 ...