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