Erlang学习总结

 

Erlang学习总结

安装,启动

基本语法

变量

保存命令的结果 X=1234565, Y = X*X*X,

erlang变量不变,单一赋值,一个变量已经赋值,叫绑定变量,否则 ,称自由变量。

整数

浮点数

必须含有小数点,且小数点后至少有一位十进制数。“/”永远返回浮点数,N

div M,用于整数除,N rem M,取余数

原子

用来表示不同的非数字常量值。是一串以小写字母开头,后跟数字字母或下划线或@的字符。例如:red,cat,joe@something,a_long_name.使用单引号引起来的也是原子,如”helloworld”

一个原子的值就是自身。

元组

将若干以逗号分割的值用一对花括号括起来。如{joe,1.82}

从元组提取字段值:

Point = {point, 10, 45}.

{point, X, Y} = Point.

X:10,Y,45

_做为匹配的占位符

列表

以逗号分隔的值,用方括号括起来。如:[1,2,3,4,5]。

列表中第一个元素为列表头,剩下的为列表的尾,,访问列表的头是一个非常高效的操作。

如果T是一个列表,则[H|T]也是一个列表。|是将列表的头和尾分隔开。

向列表增加元素[E1,E2,E3 |T]

从列表中提取元素L = [1,2,3,4,5],

[X|Y] = L,

X:1

Y:[2,3,4,5]

字符串

Name = “hello”.

记录

记录可以理解成就是元组,

当我们使用元组时,一旦元组的数量变得非常庞大,我们会很难记住元组中每一个元素的确切含义,记录就是提供了一种方法把一个名字与元组中的一个元素对应起来,从而解决这一烦恼。

模式匹配

=是一个模式匹配运算符。Lhs = Rhs,表示对右端求值,将结果与左端进行模式匹配。

X=123,将值123绑定到X.

L = [1,2,3].

[X,Y,Z] = L.

X的值1

控制语句

If 

         V1-> do(1);

         V2-> do(2)

end

 

case XXX of

         V1-> do(1);

         V2-> do(2).

end

 

无循环控制语句,替代方案:尾递归

loop() ->

    receive

        {From, {store, Key, Value}} ->

            put(Key, Value),

            io:format("store:~p,~p~n",[Key,Value]),

            From ! {kvs, true},

            loop();

        {From, {lookup, Key}} ->

            From ! {kvs, get(Key)},

            io:format("lookup:~p,~n",[Key]),

            loop()

    end.

模块

-module(modulename).

函数

同名不同目的函数,两个函数完全不同

无return 语句

异常

系统遇到错误时,就会自动地抛出异常,常见的错误:

1.      模式匹配失败

2.      调用BIF时,传入错误的类型参数

3.      调用内建的异常函数显示抛出异常:exit(Why), throw(Why), erlang:error(Why)

try generate_exception() of

         Val-> do some thing

catch

         throw:X->…..

         exit:X->….

         error:X->…

after

         Afterxpressions

end.

After后面的代码用于执行完generate_exception表达式后的清理工作,无论是否抛出异常,这段代码都必须执行。after中的返回值被自动舍弃。

并发编程

进程

使用erlang编写的应用运行时通常时成千上万个轻量级进程组成,并通过消息传递互相通讯。进程间上下文切换对于erlang来说,比C、java程序切换要高效得多。

         创建进程,

                   spawn(fun()-> loop() end).

         进程间收发消息

注册进程

register(AnAtom, Pid)

移除

unregister(AnAtom)

进程间通讯

Pid ! “Message”

链接进程

link(Pid)

unlink(Pid)

如果一个进程消亡,系统会向另一个进程发送退出信号。

监督进程

分布式编程

分布机制是透明的,对于程序来说,并不知道自己是在分布运行。利用结节的概念,整个系统的各种服务可以放在1 台机器上,也可以分布在多台机器,程序不需要改动,唯一改动的是节点名。

启动节点

erl –snamenode_a –setcookie 123

调用另一节点上的方法

rpc:call(节点名, 模块名,函数, [参数])

在远程结点启动进程

spawn(Node, fun() ->loop() end).需要把程序复制到所有节点上。dist_demo

向其他结点进程发送消息

{Node, Pid} ! “Message”.

ETS内存表,Mnesia数据库

Dist, ETS, Mnesia关系:

速度Dist > ETS >Mnesia

Dist只能在当前进程使用

ETS可以在多个进程间调用。

Mnesia可以跨越节点,分布式调用

 

ETS一般用于保存在线列表,缓存数据,Key->Value结果

Mnesia适合用于数据库存储,可直接存储Erlang数据结构,可建多个索引,并支持分片技术,可让数据均匀地分布在多个节点上。

复制是使Mnesia成为一个容错数据库管理系统的机制之一。数据表可以被复制到混合网络中的多个节点,而对应用来说却是透明的。被复制的数据表是对等的,也就是说没有主-从结构。

JAVA接口

启动节点

        OtpNodenode = newOtpNode("test","123",8888);

        OtpMboxmbox = node.createMbox();

        mbox.registerName("java");

接收erlang节点发送的消息

        OtpErlangObjectobject = mbox.receive();

回复erlang节点的消息

完整代码

    publicstaticvoid main(String[] args) throws IOException,OtpErlangExit, OtpErlangDecodeException {

        OtpNodenode = newOtpNode("test","123",8888);

        OtpMboxmbox = node.createMbox();

        mbox.registerName("java");

        System.out.println("start to Listen......");

        while(true) {

            OtpErlangObjectobject = mbox.receive();

            if(object instanceof OtpErlangTuple){

                OtpErlangTupletuple = (OtpErlangTuple) object;

                int arity =tuple.arity();

                OtpErlangPidpid = (OtpErlangPid) tuple.elementAt(0);

                System.out.println(pid);

                mbox.send(pid,newOtpErlangString("I'm node-java"));

            }

            System.out.println(object);

    }

    }

 

集群节点管理

节点特性:

         全连接

 

Mnesia数据库

启动节点

启动一个Erlang 节点并指定Mnesia数据库目录

erl -sname c -mnesia dir'"c:/Users/Administrator"'

初始化数据库模式(schema)

模式是一种特殊的表,它包含了诸如表名、每个表的存储类型(例如,表应该存储到RAM、硬盘或者可能是两者以及表的位置)等信息。

Ø  mnesia:create_schema(NodeList). 该函数用来初始化一个新的空模式,在Mnesia启动之前这是一个强制性的必要步骤。Mnesia是一个真正分布式的数据库管理系统,而模式是一个系统表,它被复制到Mnesia系统的所有节点上。如果NodeList中某一个节点已经有模式,则该函数会失败。该函数需要NodeList中所有节点上的Mnesia都停止之后才执行。应用程序只需调用该函数一次,因为通常只需要初始化数据库模式一次。

Ø  mnesia:delete_schema(DiscNodeList). 该函数在DiscNodeList节点上删除旧的模式,它也删除所有旧的表和数据。该函数需要在所有数据库节点(db_nodes)上的Mnesia都停止后才能执行。

 

启动Mnesia

mnesia:start().

 

创建表

Ø  mnesia:create_table(Name, ArgList).Name表名

Ø  mnesia:delete_table(Tab). 该函数永久删除表Tab的所有副本。

Ø  mnesia:clear_table(Tab). 该函数永久删除表Tab的全部记录。

Ø  mnesia:move_table_copy(Tab, From, To). 该函数将表Tab的拷贝从From节点移动到To节点。表的存储类型{type}被保留,这样当移动一个RAM表到另一个节点时,在新节点上也维持一个RAM表。在表移动的过程中仍然可以有事务执行读和写操作。

Ø  mnesia:add_table_copy(Tab, Node, Type). 该函数在Node节点上创建Tab表的备份。Type参数必须是ram_copies、 disc_copies或者是disc_only_copies。如果我们加一个系统表schema的拷贝到某个节点上,这意味着我们要Mnesia模式也驻留在那里。这个动作扩展了组成特定Mnesia系统节点的集合。

Ø  mnesia:del_table_copy(Tab, Node). 该函数在Node节点上删除Tab表的备份,当最后一个备份被删除后,表本身也被删除。

Ø  change_table_copy_type(Tab, Node, ToType). 该函数改变表的存储类型。例如,将在Node节点上指定的内存类型的表Tab改为磁盘类型的表.

用远程的数据模式替换本地数据库模式

mnesia:change_config(extra_db_nodes,[a@windows7]).

查看数据库的状态信息

mnesia:info()

Mnesia特性

Ø  事务属性:原子性,一致性,隔离性,持久性

Ø  索引

Ø  分片

Ø  无盘节点

 

Erlang ODBC

在系统中配置ODBC

ODBC常用操作

Ø  odbc:start().

 

{ok, Ref} = odbc:connect("DSN=name;UID=user;PWD=pwd", []).

                                                                                                                

Ø  odbc:sql_query(Ref, "CREATE TABLE EMPLOYEE (NR integer, FIRSTNAME  char varying(20), LASTNAME  char varying(20), GENDER char(1), PRIMARY KEY(NR))").

 

Ø  odbc:sql_query(Ref, "INSERT INTO EMPLOYEE VALUES(1, 'Jane', 'Doe', 'F')").

 

Ø  odbc:sql_query(Ref, "SELECT * FROM EMPLOYEE").
    {selected,["NR","FIRSTNAME","LASTNAME","GENDER"],
         [{1,"Jane","Doe","F"},
          {2,"John","Doe","M"},
          {3,"Monica","Geller","F"},
          {4,"Ross","Geller","M"},
          {5,"Rachel","Green","F"},
          {6,"Piper","Halliwell","F"},
          {7,"Prue","Halliwell","F"},                                    {8,"Louise","Lane","F"}]]}

 

Ø  关闭连接
odbc:disconnect(Ref).

 

Ø  关闭应用
odbc:stop().

Socket

打开Socket的进程被称为控制进程,socket收到的消息都会发给控制进程,如果控制进程死掉了,那这个socket也会被关掉,可以通过 gen_tcp:controlling_process(Socket, NewPid).来修改一个socket的控制进程

Ø  R11B-3 版本之后,erlang允许多个进程同时监听同一个Listen的socket,这样就可以实现创建一个pool来处理连接了

Ø  erlang 的socket可以以三种模式打开active,active once,passive,可以在gen_tcp:listen,或者gen_tcp:connect的时候设置参数{active, true | false | once}

Ø  active socket,当数据来的时候,控制进程会收到{tcp, Socket, Data}消息,控制进程无法控制什么时候收到这些消息,完全被动的,nonblocking

Ø  passive socket,控制进程必须使用gen_tcp:recv(Socket, N)明确的指定从Socket中读取N个字节,(如果N为0的话,所有可用的数据都会读出来),读取的时候是需要等待的,这样,服务器就可以完全控制什么时候读取数据,blocking

Ø  如果客户端不停的发送消息,同时服务端处理的速度跟不上的话,服务器端将会被撑死,这就是flood攻击
• 因为服务器端无法block住客户端,因此称之为nonblocking server
• 只有在确信能支撑起客户端的需要的时候才使用这种方式

Ø  服务器端可以自由的控制在需要的时候才调用recv,因此在此之前客户端将被block住(操作系统的buffer除外)
• 因此服务器端很安全,至少程序不至于被客户端疯狂的发信息而撑死(操作系统撑死除外)
• 这种阻塞模式服务器也只能等待一个socket的数据

Ø  我们使用{active,once},这样收到消息之后,socket变成passive模式,等我们处理完消息之后,再设置socket为{active,once}
• 这样,服务端不会被客户端的数据撑死了,同时也能处理很多连接的请求了

Ø  @spec inet:peername(Socket) -> {ok, {IP_Address, Port}} | {error,Why}
• 可以查看Socket的另一边是谁
• IP_Address的格式{N1,N2,N3,N4},{K1,K2,K3...K8}分别支持IPV4,IPV6,这里的N和K都是0-255的整数

Ø  Socket编程的错误处理
• 不需要错误处理!
• 如果控制进程死掉了,相应的socket就会断开,另一端会收到消息{tcp_closed,Socket}

部分例子:

start() ->

    {ok,LS}= gen_tcp:listen(8888,[{reuseaddr, true}, {packet, 0},

                       {active, false}]),

     {ok, NS} = gen_tcp:accept(LS),

    %%inet:setopts(NS, [{active, true}]),

    %%gen_tcp:controlling_process(NS, self()),

    Pid = spawn(fun() -> loop(NS) end).

    %%gen_tcp:controlling_process(NS, Pid).

    %%spawn(?MODULE, loop, [NS]).

    %%loop(NS).

 

loop(Socket) ->

    io:format("loop~n"),

    case gen_tcp:recv(Socket, 0, 5000) of

    %%receive

        {tcp,Socket,Data->

            io:format("data:~p~n",[Data]),

            gen_tcp:send(Socket, Data),

            loop(Socket);

        {tcp_closed,Socket}->

            io:format("closed~n"),

            gen_tcp:close(Socket);

        {ok,Data}->

            io:format("data:~p~n",[Data]),

            gen_tcp:send(Socket, Data),

            loop(Socket);

        {error,closed}->

            io:format("closed~n"),

            gen_tcp:close(Socket);

        Data->

            io:format("data:~p~n",[Data])

    end.

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值