2014年3月20日星期四

[]一位Erlang程序员的自白

本文自动转发自我的博客: http://www.haofengjing.org/2514.html

作者:成立涛 (litaocheng@gmail.com )

作为程序员,我们曾经闻听很多"业界动态","技术革新",曾经接触很多"高手箴言","权威推荐"。这些正确与否,都已成过去!

现在,让我们迎接 Erlang盛宴!

一、经历

2007 11月在 koders.com搜索代码时,发现 *.erl格式的源文件,感叹开发语言的花样百出,此时,我觉得 erlang是一个丑陋的小家伙,看名字就没有对它提起多少兴趣。

2008年初的时候,公司的项目开发中,我有缘认识了 ejabberd,一个采用 Erlang开发的开源 jabber服务器。我开始为其诱人的特性所倾倒。是时候认真看看Erlang到底什么样了!

2008 4月,通过各种资料的搜集,了解,我决定系统的学习 Erlang

今天,通过 4个月的认真学习,我已经熟悉了 Erlang,已经在使用 Erlang开发项目。作为 C++程序员,我不敢妄自使用"熟悉","精通"之类的字眼,但是对于 Erlang我可以很负责任的说: Erlang很巧,很强大!

二、困惑

面对一个新的事务,我们本性都会充满好奇,可是作为程序员,很多时候对于新的语言我们都充满了抵触:这个新东西值得学习么?它会不会让我抛弃旧爱?它文档丰富么?是不是很难理解?它的前景如何 ?······相信大家跟我有一样的苦恼。

但是,请听我说!我们是程序员,我们走在技术革新的最前沿。用户的产品,体验是通过我们来产生!我们不能畏缩不前,我们的固步自封,就是我们的公司,乃至整个行业的停滞不前!口号可能有些响亮,但是认真思考,我相信朋友们一定有所感悟。

三、 Erlang是什么

Erlang是什么是我们最先要面对的问题,只有清楚了它是什么,我们才能做出我们的决定。可见这个问题的重要性,它决定了很多读者是否会继续看下去!非常紧张。

Erlang最初是爱立信为开发电信相关产品而产生。

Erlang是一种面向并发 (Concurrency Oriented),面向消息( Message Oriented)的函数式 (Functional)编程语言。

面向并发说明 Erlang支持大规模的并发应用,我们可以在应用中处理成千上万的并发,而不相互影响。面向消息,其实是为并发服务!我们应该都熟悉多线程,熟悉加锁解锁操作,熟悉可能出现的资源竞争与死锁。在 Erlang的世界里,我们可以将轻轻的抹去这些令人苦恼的词汇。 Erlang的世界,每个处理都是独立的个体,他们之间的交互仅仅靠消息!因此不会有死锁,不会有那种痛苦的编程经历。

Erlang中一个非常重要的名词: Process,也就是我们前面提到的"个体"。它不是我们操作系统中的进程,也不是线程。它是 Erlang提供给我们的超级轻量的进程。为了适应大规模并发的特性, Process需要能够快速创建,快速销毁。 Process之间通信的唯一方法就是消息,我们只要知道一个 Process的名字即pid,就可以向其发送消息。 Process也可以在任何时候,接收消息。我们这样做只有一个目的:让我们的系统更加简单,用一种朴素的做法,实现一个高效的语言。

Erlang是种函数式编程语言,对此我没有很深刻的理解,最明显的特征就是, Erlang中到处都是函数,函数构成了我们的产品的主体,把这些函数放到一个个的Process中去,让他们运行起来,那么就组成了我们朝气蓬勃的产品。

Erlang支持对数据的位操作,拥有丰富的数据持久化机制。

同时需要说明的是 Erlang内建垃圾回收机制( GC)。

四、 Erlang的语言特性

1.简单小巧

Erlang中只有 8种基本的数据类型:

integer float atom reference fun port pid bitstring

同时提供 2种复合结构: tuple list,这就是 Erlang的所有数据类型。

2.模式匹配

 Erlang的函数中,某些语法中,我们可以使用 Pattern匹配,这是一个非常好的特性,我们可以让代码自己去决定如何执行 

比如,我们定义一个函数,其告诉我们某种水果的价格 :

price(apple) -> 2.0;

price(banana) -> 1.2.

我们随后调用 price(Fruit),会根据 Fruit变量的内容返回具体的价格。这样做的好处就是节省了我们的代码量,我们不用 if…else…或者 switch…case的来伺候了。也便于代码的扩展:加一个新的水果品种,我们只需要加一行就可以了。

学习 Erlang一个非常重要的内容就是模式匹配,但是请不要混淆,这个匹配和正则表达式没有任何干系。

3.变量单次赋值

这个是一个匪夷所思的特性,变量竟然只能单次赋值!是的 Erlang中变量一旦绑定某个数值以后,就不能再次绑定,这样做的好处是便于调试出错(更深层次的原因是 Erlang为并发设计,如果变量可以修改,那么就涉及到资源的加锁解锁等问题),当发生错误时,某个变量是什么就永远是什么,不用顺藤摸瓜的查找谁修改过它,省了好多事情。唯一的麻烦就是需要一个信的变量时,你必须再为它想一个名字。

4.丰富的 libs

Erlang中提供丰富的 libs

stdlib中包含大量的数据结构如 lists array dict gb_sets gb_trees ets dets

mnesia提供一个分布式的数据库系统

inets提供 ftp client http client/server tftp client/server

crypto 提供加密解密相关函数,基于 openssl相关实现

ssl 实现加密 socket通信,基于 openssl实现

ssh 实现 ssh协议

xmerl 实现 XML相关解析

snmp 实现 SNMP协议( Simple Network Management Protocol

observer 用来分析与追踪分布式应用

odbc 使 Erlang可以连接基于 SQL的数据库

orber 实现 CORBA对象请求代理服务

os_mon 提供对操作系统的监控功能

dialyzer提供一个静态的代码或程序分析工具

edoc 依据源文件生成文档

gs 可以为我们提供某些 GUI的功能(基于 Tcl/Tk

还有很多朋友提供了一些开源的 lib,比如 eunit,用来进行单元测试。

5.灵活多样的错误处理

Erlang最初为电信产品的开发,这样的目的,决定了其对错误处理的严格要求。 Erlang中提供一般语言所提供的 exception catch try…catch等语法,同时Erlang支持 Link Monitor两种机制,我们可以将 Process连接起来,让他们组成一个整体,某个 Process出错,或推出时,其他 Process都具有得知其推出的能力。而 Monitor顾名思义,可以用来监控某个 Process,判断其是否退出或出错。所有的这些 Erlang都提供内在支持,我们快速的开发坚固的产品,不在是奢望。

6.代码热替换

你的产品想不间断的更新么? Erlang可以满足你这个需求, Erlang会在运行时自动将旧的模块进行替换。一切都静悄悄。

7.天生的分布式

Erlang天生适合分布式应用开发,其很多的 BIF(内建函数,相 API)都具有分布式版本,我们可以通过 BIF在远程机器上创建 Process,可以向远程机器上的某个 Process发送消息。在分布式应用的开发中,我们可以像 C C++, JAVA等语言一样,通过 Socket进行通讯,也可以使用 Erlang内嵌的基于 Cookie的分布式架构,进行开发。当然也可以两者混合。分布式开发更加方便,快速。 Erlang Process的操作, Error的处理等都对支持分布式操作。

8.超强的并发性

由于采用其自身 Process,而没有采用操作系统的进程和线程,我们可以创建大规模的并发处理,同时还简化了我们的编程复杂度。我们可以通过几十行代码实现一个并发的 TCP服务器,这在其他语言中都想都不敢想!

9.多核支持

Erlang让您的应用支持多个处理器,您不需要为不同的硬件系统做不同的开发。采用 Erlang将最大限度的发挥你的机器性能。

10.跨平台

如同 JAVA一样, Erlang支持跨平台(其目前支持 linux mac windows 19种平台),不用为代码的移植而头疼。

我们仅仅需要了解平台的一些特性,对运行时进行优化。

11.开源

开源是我非常喜欢的一个词汇,开源意味这更加强壮,更加公开,更加的追求平等。开源会让 Erlang更好。

五、 Erlang与外界的交互

Erlang可以与其他的语言进行交互,如 C C++, Java。当然也有热心的朋友提供了与其他语言的交互,如果需要你也可以根据 Erlang的数据格式,提供一个库,让 Erang与您心爱的语言交互。

Erlang支持分布式开发,您可以创建一个 C Node,其如同一个 Erlang节点,前提是你遵照 Erlang的规范。

当然最常用的交互还是再同一个 Node上,比如我们要调用某个 lib,调用一些系统提供的功能,这时候主要有两种方式: Port和嵌入式执行。

Port Erlang最基本的与外界交互的方式,进行交互的双方通过编码,解码,将信息以字节流的方式进行传递。(具体这个通道的实现方式,根据操作系统的不同而不同,比如 unix环境下,采用 PIPE实现,理论上任何支持对应 Port通道实现的语言都可以与 Erlang进行交互)。 Erlang为了方便 C JAVA程序员,提供了 Erl_Interface Jinterface

采用 Port,您的代码在 Erlang的平台之外运行,其崩溃不会影响 Erlang

嵌入式执行,通过 Erlang平台加载,因此这是非常危险的,如果您的程序崩溃,没有任何理由, Erlang也会崩溃。

六、 Erlang应用场景

分布式产品,网络服务器,客户端,等各种应用环境。

Erlang也可以作为一种快速开发语言,进行原型开发。

七、 Erlang的学习过程

1. 安装首先从 Erlang官方网站,下载安装 Erlang http://www.erlang.org/download.html 

linux:获取源代码,根据说明编译; windows:直接安装

2. 认真阅读《 programming erlang》(中文版图书已经问世),并不断动手练习书中的例程。

3. 遇到问题时,不要退却,坚持下去找到解决办法

4. 对语言熟悉时,浏览一些好的开源项目

5. 有信心时,开始动手做一个小项目

6. 不间断的与大家交流,共同提高

可能遇到的困难:

a) 对于语法的不适应?

坚持看下去,代码继续写下去,我相信 1个月,你会喜欢上 Erlang的语法

b) 有些数据类型不清楚?

认真看资料,或者询问朋友,比如我

c) 中文资料的缺乏?

Erlang中文的资料会越来越多,此外, Erlang的相关的英文资料也比较容易理解,还是那句话,别怕麻烦


[]使用eclipse快速搭建erlang开发环境

本文自动转发自我的博客: http://www.haofengjing.org/2513.html

Erlang是一种面向并发的编程语言,可以应对大规模并发活动,将越来越受关注和使用,但是Erlang IDE却少得可怜。对比了一下,我觉得erlide比较合适。使用erlide开发环境的好处有erlang项目管理,代码自动编译,控制台调试,代码导航器等等,非常方便。下面的内容将讲述如何使用erlide开发erlang。

一、安装 erlang 和 eclipse

首先要先安装Erlang,我下载的是Erlang R16B02

erlide是eclipse的一个插件,所以使用erlide的话就要有eclipse,我下载的是Eclipse Standard 4.3.1

二、erlide 安装和配置

1、启动eclipse,进入Help → Install new software..,如下所示,填写地址 http://erlide.org/update

2、接下来,勾选要安装的插件,安装如图:

3、安装完后重启eclipse。进入Windows   Preferences后,选择Erlang →Installed runtimes,然后Add...,接着Browse..找到erlang的安装目录。如下图:

4、接着,勾选erl5.10.3,保存即可(注:没勾选eclipse报错误Editor could not be initialized.)。

这样,erlang开发环境应该搭建完成了。

三、最后语

一张图说明 erlide 开发环境的特点,有erlang项目管理,代码自动编译,控制台调试,函数导航器等等,非常方便


[]Erlang 编程简介,第 2 部分: 利用高级特性和功能

本文自动转发自我的博客: http://www.haofengjing.org/2510.html

并行编程

实现在一个程序内同时执行多个进程的能力(而非同时运行多个程序)始终要求人们改变使用传统函数编程语言时的编程方法。这种并行性(或多线程)问题在于确保您希望为其更新信息的线程,仅影响正在处理的数据和信息。举例来说,您不希望一个更新单个文件的进程多次执行,因为这可能带来文件在处理过程中被损坏的风险。

Erlang 采用了使所有程序保持并行的方法,而且组件(函数和模块)均不共享数据。数据使用消息在组件之间交换。利用消息可限制独立组件修改数据的方式,从而有助于消除并行数据修改问题。这种方法不再直接更改数据,而是发送消息来更新数据,因此也使隔离和并行更新更为困难。Erlang 还遵循操作必将失败的原则,因此提供了一种能够处理错误并在必要时从中恢复的系统。

Erlang 在内部通过创建称为进程的小型轻量级执行来处理并行性问题。不同于 C 等其他主流语言,这些进程并非构建在本地操作系统进程或线程模型之上,而是由 Erlang 虚拟机内部创建和管理。这允许各进程在内存和 CPU 需求方面比本地 OS 线程更为轻量。此外,由于 Erlang 通过自动创建和使用众多小型进程执行操作,因此即便相对较为简单的程序往往也要运行成千上万个甚至数百万个进程。

并行模型内置于 Erlang 之中,因此大量进程的管理是 Erlang 工作方式的关键组成部分。用于在进程间发送数据的消息传递系统也采用了内置形式,并设计为以非常有效的方式向任意进程分发消息,而无论当前正在运行的进程的数量如何。作为消息实现的一种附带收益,消息不仅可内部发送,还可跨网络发送,允许 Erlang 跨多个实例共享消息,从而支持多台机器间的分布式编程。

进程

Erlang 进程系统是轻量级的,进程的创建直观而简单,由于不存在开销,因此也几乎没有理由担心其影响。这就意味着您可以出于任何对应用程序有益的原因来创建新进程。

在实践中,您可以调用内置函数 spawn() 来创建进程,其调用结构如下: PID = spawn(module, function, arguments),其中 module 是模块名称、function 是函数名称、arguments 是要提供给函数的参数列表。返回值(上例中的 PID)是进程标识符。

举例来说,在本系列上一期文章中,可以使用以下格式将我们创建的 Fibonacci 函数作为新进程调用:PID = spawn(fib,printfibo,[10])

请注意,spawn() 的最后一个参数是仅有一个元素的列表,而非在直接调用函数时使用的单一参数。结果是一个新进程,将按照调用函数的方式来执行函数: fib:printfibo(10)

spawn() 创建的新进程将在终止之前继续执行,可能正常终止(即无错误),也可能非正常终止(即发生了某些错误)。

实际的生成进程本身不会失败,即便您调用的函数不存在也是如此。这能减少在代码中测试生成进程的需要。除了 Erlang shell 中的错误以外,其他进程中的错误将由错误记录程序处理和记录,这是一个处理错误报告的内置进程。

在典型使用中,进程用于支持并行性。在上述 Fibonacci 样例中,在另一个进程内运行 printfibo() 函数不会得到有用的返回值。但是,如果您希望生成一个新进程,例如基本 fibo() 函数,同时向该进程发送信息并接收该进程提供的信息,又该如何?

内置的消息传递系统可处理这样的交互。

消息传递

Erlang 中的消息传递系统是 Erlang 执行环境的另一个内置部分,它与进程系统协同工作,支持有效地交换数据和消息。

每个进程都将获得一个"邮箱",其他进程可向此邮箱发送消息。消息按照发送顺序存储,也就是说如果您从一个进程向另一个进程依次发送 A 和 B 两条消息,则消息 A 将先显示在邮箱中,消息 B 紧随其后。由于进程系统有着并行的本质,因此除了同一个进程发送的消息的独立顺序之外,多个进程发送到单独一个进程的多条消息的顺序不会按照任何特定方式排序。

要向一个进程发送一条消息,您需要了解希望与之通信的进程的进程 ID。随后可使用结构: Pid ! Message,其中 Pid 是进程 ID, Message是任意 Erlang 数据类型。

要从一个进程内接收一条消息,可使用 receive 语句。在 receive 语句内,使用模式匹配根据消息内容来确定要执行哪些操作。如果匹配成功,则从邮箱接收消息,消息参数通过绑定到匹配中的变量提供,并执行相应的子句。

举例来说,根据提供 "store" 原子(atom)和一个值的消息进行匹配的代码,如 清单 1 所示。

清单 1. 使用 receive 语句从一个进程内接收一条消息
receive      {store, Value} -> store(Value),      {get, Value} -> get(Value)  end

在本例中,代码使用模式匹配来匹配左侧的原子和变量,随后在右侧执行操作,本例中即根据消息内容存储值并获取值。

receive 语句将暂停进程中的执行,确保进程等待至新消息传入,之后再执行操作。典型的例子就是存储一个可以在多个进程之间共享的变量的基本操作。

通常,在应用程序内,您要将 receive 语句用作循环的一部分,循环渐进地读取发送给进程的新消息,并执行独立操作。Erlang 不具备传统意义上的循环,正如第一部分的 Fibonacci 示例(请参见 参考资料)所示;您需要编写一个函数,调用自身来处理消息(请参见 清单 2)。

清单 2. 调用自身来处理下一条消息的函数
dbrequest() ->      receive          {store, Value} -> store(Value),          {get, Value} -> get(Value)      end

在传统并行环境中,您可以使用信号量这样的解决方案,允许进程确定一个变量是否 "处于使用中",还是可更新。在许多环境中,信号量都给尝试更新相同值的各进程带来了等待时间,这可能会延迟程序的执行。在 Erlang 中,您可以将一个操作包含在一个进程内,随后利用消息传递来处理更新。由于消息的接收采用了队列的形式,因此可以依次处理每条消息,从而独立执行各个操作,如 图 1 所示。

图 1. 使用消息传递处理相同值的更新
本图展示了数据流:存储值、读取值、更新值,随后更新流入通过创建、检索、更新或删除与数据交互的接收的值。

这种基本的并行和消息传递结构是多种不同应用程序的基础。例如,Facebook 为 Facebook 消息传递使用了消息环境。以 MochiWeb 提供自身的 Web 界面且基于文档的数据库 CouchDB 则利用进程和消息传递系统来确保正确处理数据库更新和响应,而不会造成其他数据库往往存在的常见并行更新问题。

消息传递,尤其是在与并行处理结合时,可使程序顺序处理信息,即便存在来自不同位置的多个请求时也是如此。这解决了其他语言中典型并行编程的主要问题之一,使数据和操作可共享,而不必担心损坏或破坏进程中的信息。这种方法能够消除大多数并行编程问题存在的主要难题之一。

然而,在解决扩展解决方案、提高性能的问题方面,尤其是在现代网络和 Web 应用程序中,并行性只能为您提供这种程度的帮助。最终,您将需要多台服务器。幸运的是,Erlang 同样为这种分布式编程问题提供了解决方案。

分布式编程

Erlang 中的分布式编程基于一台简单的网络服务器和本文前述的消息传递系统构建,旨在提供发送和接收消息的机制,更重要的是,支持本地 RPC 和 Web 服务等环境支持的那类远程过程调用。

值得注意的是,分布式不一定表示不同的机器,也可能是希望彼此沟通并共享信息或操作的两个不同的 Erlang 应用程序。除了识别您正在通信的系统之外,Erlang 在一般使用中不区分系统的本地或远程特征。

为了开始使用分布式编程,首先您需要启动 Erlang,为 Erlang 的每个实例提供一个惟一名称。这样的名称将在识别过程中使用,使您能够向 Erlang 的命名实例发送消息。为了在使用 Erlang 时通过命令行设置名称,您可以使用 sname 命令行选项(请参见 清单 3)。

清单 3. 使用 sname 命令行选项
$ erl -sname one  Erlang R13B04 (erts-5.7.5) [source] [64-bit] [rq:1] [async-threads:0]    Eshell V5.7.5  (abort with ^G)  (one@mammoth)1>

请注意提示符如何更改为提供名称和主机名,这是节点的惟一标识符,可在 Erlang 中用于识别节点以及在节点间通信。

如果启动 Erlang shell 的另外一个实例,可设置另外一个不同的名称,如 清单 4 所示。

清单 4. 设置不同的名称
$ erl -sname two   Erlang R14B (erts-5.8.1) [source] [smp:8:8] [rq:8] [async-threads:0] [hipe]   [kernel-poll:false]    Eshell V5.8.1  (abort with ^G)  (two@mammoth)1>

在两个节点都运行后,即可使用 net_adm:ping() 测试一个节点能否与另一个节点通信(请参见 清单 5)。

清单 5. 使用 net_adm:ping() 测试一个节点能否与另一个节点通信
(one@mammoth)3> net_adm:ping('two@mammoth').  pong

这表明实例一可以与实例二通信。

为了在两个进程之间发送消息,您可使用修改后的消息传递操作符,在其中包含节点名称以及接收方的进程 id。例如,如果一个进程使用名称 basic 注册,您可以使用 清单 5 中的代码发送消息。可以将此代码键入之前创建的第一个 Erlang 实例的 shell 中: { basic, 'two@mammoth'} ! { self(), "message" }

在第二个主机上,如果您将当前进程(也就是 shell)注册为 "basic",随后检索可输出消息数据的消息。则将需要在实例一中发送消息之前注册当前进程(请参见 清单 6)。

清单 6. 注册当前进程
(two@mammoth)1> register(basic,self()).  true

接下来创建 receive 语句以输出消息(请参见 清单 7)。

清单 7. 创建 receive 语句来输出消息
(two@mammoth)2> receive                               (two@mammoth)2> {From,Message} -> io:format(Message ++ "~n")  (two@mammoth)2> end.  something  ok

您已经成功地在 Erlang 的两个实例间发送了消息。它们完全可能处于世界的两端,而不是相同的机器上。在两台机器之间发送消息时,发送和接收任意类型的数据都变得极为简单,只需了解进程 ID 和节点名称即可。

对于更熟悉的远程过程调用,Erlang 还支持 rpc:call() 函数: rpc:call(Node, Module, Function, Arguments)

这将调用远程节点,使用所提供的参数执行特定模块和函数,并将结果返回给调用方。rpc 模块包含允许同步、异步和阻塞调用的扩展。这是一个直接函数调用,若多个客户端同时运行此调用,则会发生并行问题,与消息传递模型相比绝非理想方法,但具体选择将取决于您的应用程序。

使用 MochiWeb

MochiWeb 是一个完整的 HTTP Web 体系,构建于 Erlang 之上。它利用了本文所述的许多 Erlang 特性,包括使用消息传递和进程来提供高性能与高级并行性。MochiWeb 利用进程系统支持并行性,利用消息来帮助处理请求和收集结果。

MochiWeb 本身结合了代码和一套脚本,使您能够迅速创建一个基本框架,您可在其中构建和扩展自己的应用程序。在最后这一部分内容中,我们将介绍如何利用 MochiWeb、设置新的 Web 服务器应用程序,以及如何将其扩展为支持您自己的应用程序。

获得 MochiWeb 的最便捷的方法就是从 GitHub 获得源代码。为此,您可以使用 git 命令,也可使用 GitHub 网站中的可下载包(请参见 参考资料)。

为了使用 git 获得源代码,请使用: $ git clone https://github.com/mochi/mochiweb.git

这将在您的当前目录中创建一个名为 mochiweb 的目录。为了使用 MochiWeb,您需要生成源代码。这将准备好 MochiWeb 以便您创建新的 MochiWeb 应用程序。

为此,首先在 mochiweb 目录中运行 make 命令,如 清单 8 所示。

清单 8. 生成资源
$ cd mochiweb $ make  ==> mochiweb (get-deps)  ==> mochiweb (compile)  Compiled src/mochiweb_sup.erl  Compiled src/mochifmt.erl  Compiled src/mochiweb_charref.erl  Compiled src/mochiweb_request_tests.erl  Compiled src/mochifmt_records.erl  Compiled src/mochiweb_socket.erl  Compiled src/mochiweb_app.erl  Compiled src/mochiweb_io.erl  Compiled src/mochifmt_std.erl  Compiled src/mochiglobal.erl  Compiled src/mochiweb_socket_server.erl  Compiled src/mochijson.erl  Compiled src/mochihex.erl  Compiled src/mochiweb_html.erl  Compiled src/mochiweb_multipart.erl  Compiled src/mochilogfile2.erl  Compiled src/mochiweb_cover.erl  Compiled src/mochiweb_util.erl  Compiled src/mochitemp.erl  Compiled src/reloader.erl  Compiled src/mochinum.erl  Compiled src/mochiweb_headers.erl  Compiled src/mochiweb_skel.erl  Compiled src/mochiutf8.erl  Compiled src/mochiweb_echo.erl  Compiled src/mochiweb_acceptor.erl  Compiled src/mochiweb_http.erl  Compiled src/mochijson2.erl  Compiled src/mochiweb_cookies.erl  Compiled src/mochiweb.erl  Compiled src/mochiweb_mime.erl  Compiled src/mochilists.erl  Compiled src/mochiweb_response.erl  Compiled src/mochiweb_request.erl

这就完成了 mochiweb 源代码的编译。为了创建一个示例应用程序框架,以便用于构建我们自己的 Web 服务器,您将再一次使用 make 来生成新项目目录。PROJECT 将成为项目和目录名称,PREFIX 将成为在其中创建新 PROJECT 目录的目录名称。例如,要创建一个名为 mywebserver 的项目: $ make app PROJECT=mywebserver PREFIX=../

上面的代码行将在父目录内创建一个新的 MochiWeb 应用程序(也就是说,与 mochiweb 相同的级别)。

新创建的目录是一个基本 Web 服务器,它将默认侦听 8080 端口(在所有接口上)。要生成应用程序,请再次运行 make,确保编译 MochiWeb 组件和各应用程序:

$ cd ../mywebserver  $ make

最后,运行 start-dev.sh script 来运行基本应用程序。这将生成大量输出,所有这些输出都是 "进度报告",表示创建用于处理 Web 服务器的各进程。如果输出中未报告任何错误,则 Web 服务器即可正常运行(请参见 清单 9)。

清单 9. Web 服务器正常运行
Erlang R13B04 (erts-5.7.5) [source] [64-bit] [rq:1] [async-threads:0]    =PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===            supervisor: {local,sasl_safe_sup}               started: [{pid,<0.42.0>},                         {name,alarm_handler},                         {mfa,{alarm_handler,start_link,[]}},                         {restart_type,permanent},                         {shutdown,2000},                         {child_type,worker}]    =PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===            supervisor: {local,sasl_safe_sup}               started: [{pid,<0.43.0>},                         {name,overload},                         {mfa,{overload,start_link,[]}},                         {restart_type,permanent},                         {shutdown,2000},                         {child_type,worker}]    =PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===            supervisor: {local,sasl_sup}               started: [{pid,<0.41.0>},                         {name,sasl_safe_sup},                         {mfa,                             {supervisor,start_link,                                 [{local,sasl_safe_sup},sasl,safe]}},                         {restart_type,permanent},                         {shutdown,infinity},                         {child_type,supervisor}]    =PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===            supervisor: {local,sasl_sup}               started: [{pid,<0.44.0>},                         {name,release_handler},                         {mfa,{release_handler,start_link,[]}},                         {restart_type,permanent},                         {shutdown,2000},                         {child_type,worker}]    =PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===           application: sasl            started_at: mywebserver_dev@localhost  Eshell V5.7.5  (abort with ^G)  (mywebserver_dev@localhost)1> ** Found 0 name clashes in code paths     =PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===            supervisor: {local,crypto_sup}               started: [{pid,<0.54.0>},                         {name,crypto_server},                         {mfa,{crypto_server,start_link,[]}},                         {restart_type,permanent},                         {shutdown,2000},                         {child_type,worker}]    =PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===           application: crypto            started_at: mywebserver_dev@localhost  ** Found 0 name clashes in code paths     =PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===            supervisor: {local,mywebserver_sup}               started: [{pid,<0.59.0>},                         {name,mywebserver_web},                         {mfa,                             {mywebserver_web,start,                                 [[{ip,{0,0,0,0}},                                   {port,8080},                                   {docroot,                                       "/root/mybase/mywebserver/priv/www"}]]}},                         {restart_type,permanent},                         {shutdown,5000},                         {child_type,worker}]    =PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===           application: mywebserver            started_at: mywebserver_dev@localhost    =PROGRESS REPORT==== 7-Apr-2011::11:40:36 ===            supervisor: {local,kernel_safe_sup}               started: [{pid,<0.77.0>},                         {name,timer_server},                         {mfa,{timer,start_link,[]}},                         {restart_type,permanent},                         {shutdown,1000},                         {child_type,worker}]

您可以打开 Web 浏览器,尝试访问新的 Web 服务器。如果该 Web 服务器处于相同的机器上,您可打开 http://localhost:8080/。如果一切正常工作,您应看到一个页面,标题为 "It Worked",其中包含的消息为 "webserver running."。

如果您希望修改新服务器,可以在应用程序目录中编辑 src/mywebserver_web.erl 文件。此文件中包含运行和支持 Web 服务的核心代码。

进程的核心是 loop() 函数,MochiWeb 主系统每次接收到一条请求时都会调用此函数。此函数提供两个参数,请求结构(其中包含请求类型、路径和任意主体数据)以及 DocRoot。后者必不可少,因为服务器默认将从指定文档根下的文件系统中提供所请求的文件。

请求的处理分为两个阶段,首先使用 case 语句提取请求类型(GETPOST 等)。随后,使用第二条 case 语句来识别请求的路径。

您可以使用 Erlang 中的模式匹配,因此一端的路径可触发特定响应。举例来说,可以修改代码,使得对于服务器上 /hello 路径的访问返回短语 "Hello world",如 清单 10 所示。

清单 10. Erlang 中的模式匹配
loop(Req, DocRoot) ->      "/" ++ Path = Req:get(path),      try          case Req:get(method) of              Method when Method =:= 'GET'; Method =:= 'HEAD' ->                  case Path of                      "congrat" ->                          Req:ok({"text/html", [],["<h1>Congratulation  </h1>"]});                      "hello" ->                          Req:ok({"text/plain",[],["Hello world"]});                      _ ->                          Req:serve_file(Path, DocRoot)                  end;              'POST' ->                  case Path of                      _ ->                          Req:not_found()                  end;              _ ->                  Req:respond({501, [], []})          end      catch          Type:What ->              Report = ["web request failed",                        {path, Path},                        {type, Type}, {what, What},                        {trace, erlang:get_stacktrace()}],              error_logger:error_report(Report),              %% NOTE: mustache templates need \ because they are not awesome.              Req:respond({500, [{"Content-Type", "text/plain"}],                           "request failed, sorry\n"})      end.

编辑好文件之后,请确保运行 make,重新生成应用程序,随后使用 start-dev.sh 脚本重新启动应用程序。

现在,如果使用 http://localhost:8080/hello 访问您的 Web 服务器的 URL,您应得到 hello world 消息。

尽管这只是一个基本的示例,但您能看到,通过寻找 POST 或 PUT 请求、处理文档正文、随后存储信息,基本 REST 服务支持等新功能的添加即可轻松实现。使用衍生进程和消息传递,您就可以对来自服务器的请求进行排队,以便存储、更新和检索信息。

结束语

Erlang 曾经用于电话交换机环境中,这也就意味着该语言的核心功能是在与其他大多数语言完全不同的环境中开发的。运行和创建多个进程来处理大量并行操作(例如,电话呼叫)的问题也内置于此语言之中。

通过利用内置的消息传递系统,通过一种无破坏性、也不需要复杂信号量系统在进程间共享信息的方法,创建新进程并在进程间通信的过程即可得到简化。由于消息传递是顺序的,因此各进程间的通信将易于处理。此外,消息系统跨 Erlang 实例、通过网络操作,这使得跨机器通信更为简单直观。

MochiWeb 将大多数此类功能结合在一起,提供了一种高性能、高可伸缩的 Web 服务器解决方案,也可轻松扩展和延伸为支持额外的功能,所需工作量极少。

参考资料

学习

获得产品和技术

  • MochiWeb:GitHub 托管的 Erlang 库,用于构建轻量级的 HTTP 服务器。
  • Erlang:下载 Erlang 编程语言。
  • Apache CouchDB 项目:CouchDB 是使用 MochiWeb HTTP 服务器用 Erlang 编写的,可以从 Apache 获取它。

2014年3月19日星期三

[]如何查询SQL Server 数据库版本号

本文自动转发自我的博客: http://www.haofengjing.org/2509.html

  使用 SQL Server Management Studio 连接到 SQL Server 2005,然后运行以下 Transact-SQL 语句:

SELECT  SERVERPROPERTY('productversion'), SERVERPROPERTY ('productlevel'), SERVERPROPERTY ('edition') 运行结果如下: ? 产品版本(例如,"9.00.1399.06")。 ? 产品级别(例如,"RTM")。 ? 版本(例如,"Enterprise Edition")。 例如,运行结果可能类似于如下内容: 9.00.1399.06 RTM Enterprise Edition 下表列出了 Sqlservr.exe 的版本号: 发行版                                 Sqlservr.exe RTM                                    2005.90.1399 SQL Server 2005 Service Pack 1         2005.90.2047


[] 深入淺出 Android -- Google 手持設備應用程式設計入門 - BMI (Body Mass Index) Calculator App on Android platform

本文自动转发自我的博客: http://www.haofengjing.org/2498.html
台湾的作者gasolin,不错的入门级教学材料。网站访问地址是:   http://code.google.com/p/androidbmi/wiki/DiveIntoAndroid