OTP服务器

defmodule Sequence.Server do
    use GenServer

    def handle_call( :next_number, _from, current_number) do
        { :reply, current_number, current_number + 1}  #reply告诉OTP将第二个元素返回给客户端
    end
end

  use的效果将OTP GenServer的行为添加到当前模块。这样它就可以处理所有的回调函数。这也意味着我们不需要在模块中定义所有的回调函数——该行为定义了所有默认的回调函数。

  当客户端调用服务器时,GenServer调用接下来的hand_call函数。它接受:1、客户端传递给调用的信息。2、客户端的PID。3、服务器状态。    

  其返回一个元组给OTP { :reply, current_number, current_number + 1 },reply告诉OTP需要回复客户端,第二个是返回值,第三个定义了新的状态。该状态子在handle_call下次被调用时作为最后一个参数传入。

  

  启动服务器:

iex -S mix
{ :ok, pid } = GenServer.start_link(Sequence.Server, 100)    #100是状态,相当于该进程的一个属性。

GenServer.call( pid, :next_number )        # 100
GenServer.call( pid, :next_number )        # 101

  start_link函数的行为类似于spawn_link。它要求GenServer创建一个新的进程并与我们相关联,并传递了一个状态值进去。返回服务器的pid

  call调用pid进程里的handle_call函数,将其第二个参数(:next_number )与handle_call的第一个参数做匹配。handle_call的第一个参数也可以是元组。

def handle_call({ :set_number, new_number}, _form, _current_number ) do
    {:reply, new_number, new_number }
end

然后这样调用
GenServer.call(pid, {:set_number, 999} )        # 999

 

cast

  cast函数调用服务器,但不等待回复。cast发送给handle_cast,由于可能没有相应,所以handle_cast只需要两个参数。放弃了第二个代表客户端pid的参数。其返回元组为{ :noreply, new_state }

defmodule Sequence.Server do
    use GenServer

    def handle_call( :next_number, _from, current_number) do
        { :reply, current_number, current_number + 1}
    end

    def handle_cast({:increment_number, delta}, current_number) do
        { :noreply, current_number + delta}
    end
end

GenServer.call(pid, :next_number)      #100
GenServer.call(pid, :next_number)    #101
GenServer.cast(pid, {:increment_number, 200})    # :ok
GenServer.call(pid, :next_number)      #302

 

回调函数

  init(start_arguments)。当GenServer启动服务器时被调用,默认将服务器状态设置为出入参数的值。

  handle_call(request, from, state)。客户端使用GenServer.call(pid, request)时被调用。成功返回{ :reply, result, new_state }

  handle_cast(request, state)。用于响应GenServer.cast(pid, request)。成功的相应是{ :noreply, new_state },也能返回{ :stop, reason, new_state }

  handle_info(info, state)。用于处理call和cast以外的传入消息。

  terminate(reason, state)。当服务器将终止时该函数被调用。

  code_change(from_version, state, extra)。理由OTP替换正在运行的服务器而无需停止整个系统。

  format_status(reason, [pdict, state])。定制服务器的状态显示。

 

给进程命名

  启动服务器的时候加上 name:参数 。

{ :ok, pid } = GenServer.start_link(Sequence.Server, 100, name::seq)
GenServer.call(:seq, :next_number)

 

整理接口

  

defmodule Sequence do
    use GenServer

    def start_link(current_number) do
        GenServer.start_link(__MODULE__, current_number, name: __MODULE__)
    end
    
    def next_number do
        GenServer.call __MODULE__, next_number
    end

    def increment_number(delta) do
        GenServer.call __MODULE__, {:increment_number, delta}
    end


    def handle_call( :next_number, _from, current_number) do
        { :reply, current_number, current_number + 1}
    end

    def handle_cast({:increment_number, delta}, current_number) do
        { :noreply, current_number + delta}
    end
end

 

posted @ 2019-09-12 15:58  GodL  阅读(793)  评论(0编辑  收藏  举报