- 浏览: 2678154 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
80后的童年2:
深入浅出MongoDB应用实战开发网盘地址:https://p ...
MongoDB入门教程 -
shliujing:
楼主在不是精通java和php的前提下,请不要妄下结论。
PHP、CakePHP哪凉快哪呆着去 -
安静听歌:
希望可以一给一点点注释
MySQL存储过程之代码块、条件控制、迭代 -
qq287767957:
PHP是全宇宙最强的语言!
PHP、CakePHP哪凉快哪呆着去 -
rryymmoK:
深入浅出MongoDB应用实战开发百度网盘下载:链接:http ...
MongoDB入门教程
原文: Erlang: A Generalized TCP Server
前面几篇文章里谈到了Erlang的gen_tcp网络编程和Erlang/OPT的gen_server模块,现在让我们将它们两者绑定在一起
大多数人认为“服务器”意味着网络服务器,但Erlang使用这个术语时表达的是更抽象的意义
gen_serer在Erlang里是基于它的消息传递协议来操作的服务器,我们可以在此基础上嫁接一个TCP服务器,但这需要一些工作
网络服务器的结构
大部分网络服务器有相似的架构
首先它们创建一个监听socket来监听接收的连接
然后它们进入一个接收状态,在这里一直循环接收新的连接,直到结束(结束表示连接已经到达并开始真正的client/server工作)
先看看前面网络编程里的echo server的例子:
你可以看到,listen会创建一个监听socket并马上调用accept
accept会等待进来的连接,创建一个新的worker(loop)来处理真正的工作,然后等待下一个连接
在这部分代码里,父进程拥有listen socket和accept loop两者
后面我们会看到,如果我们集成accept/listen loop和gen_server的话这样做并不好
抽象网络服务器
网络服务器有两部分:连接处理和业务逻辑
上面讲到,连接处理对每个网络服务器都是几乎一样的
理想状态下我们可以这样做:
让我们继续完成它
实现一个通用网络服务器
使用gen_server来实现一个网络服务器的问题是,gen_tcp:accept调用是堵塞的
如果我们在服务器的初始化例程里调用它,那么整个gen_server机制都会堵塞,直到客户端建立连接
有两种方式来绕过这个问题
一种方式为使用低级连接机制来支持非堵塞(或异步)accept
有许多方法来支持这样做,最值得注意的是gen_tcp:controlling_process,它帮你管理当客户端建立连接时谁接受了什么消息
我认为另一种比较简单而更优雅的方式是,一个单独的进程来监听socket
该进程做两件事:监听“接收连接”消息以及分配新的接收器
当它接收一条新的“接收连接”的消息时,就知道该分配新的接收器了
接收器可以任意调用堵塞的gen_tcp:accept,因为它允许在自己的进程里
当它接受一个连接后,它发出一条异步消息传回给父进程,并且立即调用业务逻辑方法
这里是代码,我加了一些注释,希望可读性还可以:
我们使用gen_server:cast来传递异步消息给监听进程,当监听进程接受accepted消息后,它分配一个新的接收器
目前,这个服务器不是很健壮,因为如果无论什么原因活动的接收器失败以后,服务器会停止接收新的连接
为了让它变得更像OTP,我们因该捕获异常退出并且在连接失败时分配新的接收器
一个通用的echo服务器
echo服务器是最简单的服务器,让我们使用我们新的抽象socket服务器来写它:
你可以看到,服务器只含有自己的业务逻辑
连接处理被封装到socket_server里面
而这里的loop方法也和最初的echo服务器一样
希望你可以从中学到点什么,我觉得我开始理解Erlang了
欢迎回复,特别关于是如何改进我的代码,cheers!
前面几篇文章里谈到了Erlang的gen_tcp网络编程和Erlang/OPT的gen_server模块,现在让我们将它们两者绑定在一起
大多数人认为“服务器”意味着网络服务器,但Erlang使用这个术语时表达的是更抽象的意义
gen_serer在Erlang里是基于它的消息传递协议来操作的服务器,我们可以在此基础上嫁接一个TCP服务器,但这需要一些工作
网络服务器的结构
大部分网络服务器有相似的架构
首先它们创建一个监听socket来监听接收的连接
然后它们进入一个接收状态,在这里一直循环接收新的连接,直到结束(结束表示连接已经到达并开始真正的client/server工作)
先看看前面网络编程里的echo server的例子:
-module(echo). -author('Jesse E.I. Farmer <jesse@20bits.com>'). -export([listen/1]). -define(TCP_OPTIONS, [binary, {packet, 0}, {active, false}, {reuseaddr, true}]). % Call echo:listen(Port) to start the service. listen(Port) -> {ok, LSocket} = gen_tcp:listen(Port, ?TCP_OPTIONS), accept(LSocket). % Wait for incoming connections and spawn the echo loop when we get one. accept(LSocket) -> {ok, Socket} = gen_tcp:accept(LSocket), spawn(fun() -> loop(Socket) end), accept(LSocket). % Echo back whatever data we receive on Socket. loop(Socket) -> case gen_tcp:recv(Socket, 0) of {ok, Data} -> gen_tcp:send(Socket, Data), loop(Socket); {error, closed} -> ok end.
你可以看到,listen会创建一个监听socket并马上调用accept
accept会等待进来的连接,创建一个新的worker(loop)来处理真正的工作,然后等待下一个连接
在这部分代码里,父进程拥有listen socket和accept loop两者
后面我们会看到,如果我们集成accept/listen loop和gen_server的话这样做并不好
抽象网络服务器
网络服务器有两部分:连接处理和业务逻辑
上面讲到,连接处理对每个网络服务器都是几乎一样的
理想状态下我们可以这样做:
-module(my_server). start(Port) -> connection_handler:start(my_server, Port, businees_logic). business_logic(Socket) -> % Read data from the network socket and do our thang!
让我们继续完成它
实现一个通用网络服务器
使用gen_server来实现一个网络服务器的问题是,gen_tcp:accept调用是堵塞的
如果我们在服务器的初始化例程里调用它,那么整个gen_server机制都会堵塞,直到客户端建立连接
有两种方式来绕过这个问题
一种方式为使用低级连接机制来支持非堵塞(或异步)accept
有许多方法来支持这样做,最值得注意的是gen_tcp:controlling_process,它帮你管理当客户端建立连接时谁接受了什么消息
我认为另一种比较简单而更优雅的方式是,一个单独的进程来监听socket
该进程做两件事:监听“接收连接”消息以及分配新的接收器
当它接收一条新的“接收连接”的消息时,就知道该分配新的接收器了
接收器可以任意调用堵塞的gen_tcp:accept,因为它允许在自己的进程里
当它接受一个连接后,它发出一条异步消息传回给父进程,并且立即调用业务逻辑方法
这里是代码,我加了一些注释,希望可读性还可以:
-module(socket_server). -author('Jesse E.I. Farmer <jesse@20bits.com>'). -behavior(gen_server). -export([init/1, code_change/3, handle_call/3, handle_cast/2, handle_info/2, terminate/2]). -export([accept_loop/1]). -export([start/3]). -define(TCP_OPTIONS, [binary, {packet, 0}, {active, false}, {reuseaddr, true}]). -record(server_state, { port, loop, ip=any, lsocket=null}). start(Name, Port, Loop) -> State = #server_state{port = Port, loop = Loop}, gen_server:start_link({local, Name}, ?MODULE, State, []). init(State = #server_state{port=Port}) -> case gen_tcp:listen(Port, ?TCP_OPTIONS) of {ok, LSocket} -> NewState = State#server_state{lsocket = LSocket}, {ok, accept(NewState)}; {error, Reason} -> {stop, Reason} end. handle_cast({accepted, _Pid}, State=#server_state{}) -> {noreply, accept(State)}. accept_loop({Server, LSocket, {M, F}}) -> {ok, Socket} = gen_tcp:accept(LSocket), % Let the server spawn a new process and replace this loop % with the echo loop, to avoid blocking gen_server:cast(Server, {accepted, self()}), M:F(Socket). % To be more robust we should be using spawn_link and trapping exits accept(State = #server_state{lsocket=LSocket, loop = Loop}) -> proc_lib:spawn(?MODULE, accept_loop, [{self(), LSocket, Loop}]), State. % These are just here to suppress warnings. handle_call(_Msg, _Caller, State) -> {noreply, State}. handle_info(_Msg, Library) -> {noreply, Library}. terminate(_Reason, _Library) -> ok. code_change(_OldVersion, Library, _Extra) -> {ok, Library}.
我们使用gen_server:cast来传递异步消息给监听进程,当监听进程接受accepted消息后,它分配一个新的接收器
目前,这个服务器不是很健壮,因为如果无论什么原因活动的接收器失败以后,服务器会停止接收新的连接
为了让它变得更像OTP,我们因该捕获异常退出并且在连接失败时分配新的接收器
一个通用的echo服务器
echo服务器是最简单的服务器,让我们使用我们新的抽象socket服务器来写它:
-module(echo_server). -author('Jesse E.I. Farmer <jesse@20bits.com>'). -export([start/0, loop/1]). % echo_server specific code start() -> socket_server:start(?MODULE, 7000, {?MODULE, loop}). loop(Socket) -> case gen_tcp:recv(Socket, 0) of {ok, Data} -> gen_tcp:send(Socket, Data), loop(Socket); {error, closed} -> ok end.
你可以看到,服务器只含有自己的业务逻辑
连接处理被封装到socket_server里面
而这里的loop方法也和最初的echo服务器一样
希望你可以从中学到点什么,我觉得我开始理解Erlang了
欢迎回复,特别关于是如何改进我的代码,cheers!
发表评论
-
ECUG III -- Elrang中国用户组第三次活动
2008-11-06 11:00 2232详情请见: http://ecug.org/ 大家也帮忙宣传 ... -
Erlang内存管理和运行模式笔记
2008-09-25 16:40 5378Erlang进程非常轻量级 进程间通过消息传递进行通讯 进程接 ... -
Erlang里的make
2008-09-22 17:38 3726Erlang自带一个make工具 我们看一个例子 目录结构: ... -
介绍Erlang里的Record
2008-09-12 15:52 8579原文: Erlang: An Introduction to ... -
Erlang与ActionScript3采用JSON格式进行Socket通讯
2008-09-02 16:37 6275前提: 需要下载as3corelib来为ActionScrip ... -
Erlang的JSON库
2008-09-02 15:40 9341使用下列JSON库: http://www.lshift.ne ... -
Erlang和ActionScript3的Socket通讯
2008-09-02 13:18 2874server.erl -module(server). ... -
Erlang和Ruby的Socket通讯
2008-09-01 22:12 2315server.erl -module(server). ... -
Erlang实现简单Web服务器
2008-09-01 17:59 5775转贴一个简单的Web服务器: httpd.erl %% h ... -
Mnesia用户手册:五,Mnesia高级特性
2008-09-01 17:27 7045本章描述了构建分布式、容错的Mnesia数据库相关的高级特性: ... -
Mnesia用户手册:四,事务和其他访问上下文
2008-08-29 00:06 6793本章讲述Mnesia事务系统和事务属性,它们让Mnesia成为 ... -
Mnesia用户手册:三,构建Mnesia数据库
2008-08-27 21:46 9201本章详细介绍了设计Mnes ... -
Mnesia用户手册:二,Mnesia快速上手
2008-08-27 14:09 9092本章介绍了Mnesia: 1) ... -
Mnesia用户手册:一,介绍
2008-08-26 15:47 7778Mnesia是一个分布式数据 ... -
OTP Design Principles: Supervisor Behaviour
2008-08-26 00:06 3090Supervisor Behaviour是一个用来实现一个su ... -
gen_event例子:terminal_logger
2008-08-25 16:23 1654定义三个terminal_logger: $$ termina ... -
OTP Design Principles: Gen_Event Behaviour
2008-08-25 16:06 17941,事件处理原则 在OTP里,event manager是一个 ... -
gen_fsm例子:code_lock
2008-08-22 18:35 2127改了一下代码,可以run了: %% code_lock.erl ... -
OTP Design Principles: Gen_Fsm Behaviour
2008-08-22 17:29 18101,有限状态机 FSM,有 ... -
gen_server Hello World
2008-08-22 13:45 1682简单的gen_server Hello World程序 代码 ...
相关推荐
aberth-用Erlang编写的通用BERT-RPC服务器版权所有(c)2014 Aleksandar Radulovic。 版本: 0.9 aberth是Erlang中的通用BERT-RPC服务器。 它公开了常规的erlang模块,并使用作为TCP接受者...创建一个简单的模块(或两
2. **并发执行**:Erlang和Elixir的并发模型基于轻量级进程(processes),gen-batch-server可以同时处理多个任务,每个任务在一个独立的进程中运行,确保任务间的隔离和并发性能。 3. **错误处理**:gen-batch-...
通用 TCP 服务器 通用 TCP 服务器( gen_tcp_server ) 是一种 Erlang 行为,提供快速简便的方法将 TCP 服务器功能添加到您的应用程序。 它被实现为管理 TCP 连接的主管,因为它是孩子。如何使用它? 运行make来构建。...
版本24.3.4.4是Erlang的一个更新版本,包含了对先前版本的改进和修复。Erlang以其强大的错误恢复能力和轻量级进程(称为Erlang进程)而闻名,这些进程具有内置的并发性和容错性。 在安装Erlang 24.3.4.4之前,首先...
总结起来,"otp_src_21.3.tar.gz"是一个包含Erlang OTP框架源代码的压缩包,对于理解Erlang并发模型、开发基于OTP的系统以及搭建RabbitMQ服务器至关重要。通过学习和使用这些资源,开发者可以构建出高效、健壮的...
STDLIB是Erlang的一个核心模块,包含了各种通用的函数库,如列表操作、字符串处理、文件系统交互等。它为开发者提供了一个全面而强大的工具箱,使得编写高效可靠的Erlang程序变得更加容易。根据文档,STDLIB 1.17.4...
2. **GenServer行为**:在Erlang中,GenServer是一种通用服务器行为,用于处理异步请求并保持状态。创建TCP服务器时,通常会实现一个GenServer过程来管理连接和处理客户端请求。 3. **inet模块**:Erlang的inet模块...
本篇将基于提供的标题“自己写一个tcp 通用服务器”来深入探讨如何创建一个自定义的TCP服务器,并结合描述中的博文链接和标签“源码 工具”,我们将分析提供的源码文件。 首先,让我们了解TCP服务器的基本工作原理...
- **行为模式**:如GenServer、GenEvent和Gen_fsm,它们定义了Erlang中服务器、事件处理和状态机的通用行为。 - **Elixir**:基于Erlang VM的现代编程语言,提供了更接近Ruby的语法,同时保留了Erlang的并发特性和...
gen_server是Erlang OTP(开放电信平台)设计模式之一,它为服务器进程提供了一个通用框架,处理请求、状态管理和错误处理。在聊天室应用中,gen_server可以被用来管理用户登录、保持用户状态、接收和转发消息。每个...
4. **OTP(开放电信平台)**:OTP是Erlang生态系统中的一个重要组成部分,包含大量库和设计模式,用于解决网络和电信系统中的常见问题。它提供了行为模式(如GenServer、GenEvent和Supervisor),帮助开发者构建健壮...
当一个进程崩溃时,它能够被自动重启,以确保系统的稳定性和可靠性。 3. **分布式应用**:编写分布式应用程序在Erlang中非常简单。其分布机制是透明的,这意味着程序无需了解它们是否在不同的机器上执行。这种特性...
- **实践项目**: 结合实际案例进行练习,比如实现一个简单的 Web 服务器或聊天应用,通过实践加深对 Erlang 特性的理解。 - **社区交流**: 加入 Erlang 社区,与其他开发者交流经验和技术问题,参与开源项目也是提高...
特征通用非阻塞TCP / SSL套接字服务器接受者池和异步TCP接受UDP / DTLS服务器最大连接管理通过对等地址允许/拒绝代理协议V1 / V2 Keepalive支持速率限制IPv6支持用法一个简单的TCP Echo服务器: -module(echo_server...
根据提供的文件信息,我们可以提取并总结出以下几个关键的知识点: ### 1. 关于Erlang编程语言 **Erlang**是一种通用、并发、容错的编程语言...对于希望了解或学习Erlang的开发者来说,这本书是一个宝贵的学习资源。
Erlang OTP 19.1 是一个重要的版本更新,主要包含了Erlang编程语言的运行时系统(ERTS)和其他一系列的库和工具。OTP(Open Telecom Platform)是Erlang的核心部分,提供了一个强大的框架来构建高度并发、容错和...
- **启动Erlang Shell**:安装完成后,可以通过命令行工具启动Erlang Shell,这是一个交互式的Erlang解释器环境。 - **基本语法介绍**: - **整数运算**:Erlang支持基本的算术运算符,例如加减乘除。 - **变量...
6. **在`YAWS`中调用**:`YAWS`是`Erlang`的一个Web服务器,它可以嵌入到`Erlang`应用中。如果你的`YAWS`应用需要调用`J2EE`服务,你可以在`YAWS`的回调函数中插入`Jinterface`的调用代码。这样,每次HTTP请求到达时...