defmodule Sequence.Server douse GenServerdef 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 douse GenServerdef handle_call( :next_number, _from, current_number) do{ :reply, current_number, current_number + 1}enddef handle_cast({:increment_number, delta}, current_number) do{ :noreply, current_number + delta}end endGenServer.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 douse GenServerdef start_link(current_number) doGenServer.start_link(__MODULE__, current_number, name: __MODULE__)enddef next_number doGenServer.call __MODULE__, next_numberenddef increment_number(delta) doGenServer.call __MODULE__, {:increment_number, delta}enddef handle_call( :next_number, _from, current_number) do{ :reply, current_number, current_number + 1}enddef handle_cast({:increment_number, delta}, current_number) do{ :noreply, current_number + delta}end end
?