我通過使用Erlang :gen_tcp模塊的實現在Phoenixframwork中開發了一個TCP服務器。從Elixir的tcp服務器向打開的連接中的tcp客戶端發送消息
我可以通過調用:gen_tcp.listen(port)
啓動服務器,然後在此端口上監聽新的連接。
一個客戶端是藥房的自動採摘系統(基本上是一個自動藥物分配機器人)。
所以作爲一個tcp客戶端,機器人能夠打開到我的tcp服務器的連接。服務器通過機器人通過handle_info
回調方法偵聽新消息,並且還能夠在此請求(:gen_tcp.send
)內響應客戶機。
我面臨的問題是,我不知道如何使用這個連接,併發送數據回機器人沒有客戶端請求。
由於機器人是一個tcp客戶端(機器人後面的公司說目前沒有辦法讓機器人充當服務器),所以沒有可以發送消息的開放端口/機器人服務器地址。所以我必須使用由客戶端初始化的已建立的連接。
設置
pharmacy_ui> pharmacy_api(菲尼克斯)>機器人(供應商軟件)
工作流:
- 機器人初始化通過TCP到API的連接
- 機器人發送狀態信息給API並得到響應
- 在某些點(見更新1),該API必須發送一個分配請求到機器人(通過使用在#1初始化的連接)
步驟1和2工作,第3部分沒有按」噸。
這看起來像關於藥劑/鳳凰TCP連接一個相當簡單的問題,但在正確的方向任何暗示的高度讚賞:)
到目前爲止,我來到了這個實現(在此基礎上blog post):
defmodule MyApi.TcpServerClean do
use GenServer
defmodule State do
defstruct port: nil, lsock: nil, request_count: 0
end
def start_link(port) do
:gen_server.start_link({ :local, :my_api }, __MODULE__, port, [])
end
def start_link() do
start_link 9876 # Default Port if non provided at startup
end
def get_count() do # test call from my_frontend
:gen_server.call(:my_api, :get_count)
end
def stop() do
:gen_server.cast(:my_api, :stop)
end
def init (port) do
{ :ok, lsock } = :gen_tcp.listen(port, [{ :active, true }])
{ :ok, %State{lsock: lsock, port: port}, 0 }
end
def handle_call(:get_count, _from, state) do
{ :reply, { :ok, state.request_count }, state }
end
def handle_cast(:stop , state) do
{ :noreply, state }
end
# handles client tcp requests
def handle_info({ :tcp, socket, raw_data}, state) do
do_rpc(socket, raw_data) # raw_data = data from robot
{ :noreply, %{ state | request_count: state.request_count + 1 } } # count for testing states
end
def handle_info(:timeout, state) do
{ :ok, _sock } = :gen_tcp.accept state.lsock
{ :noreply, state }
end
def handle_info(:tcp_closed, state) do
# do something
{ :noreply, state }
end
def do_rpc(socket, raw_data) do
try do
# process data from robot and do something with it
resp = "My tcp server response ..." # test
:gen_tcp.send(socket, :io_lib.fwrite(resp, []))
catch
error -> :gen_tcp.send(socket, :io_lib.fwrite("~p~n", [error]))
end
end
end
更新1:
在某些點= A用戶(例如藥劑師)放置在UI前端的順序。前端觸發到api的帖子,並且api處理OrderController中的帖子。 OrderController必須轉換順序(以便機器人理解它)並將其傳遞給保存到機器人連接的TcpServer。這個工作流程每天會發生多次。
你可以舉一個「在某個時間點」的例子嗎?誰會觸發這個動作?一個簡短的答案是你可以產生一個存儲套接字的進程(像一個不同的'GenServer'),等待觸發器,然後發送一個響應,如果你希望'TcpServerClean'能夠同時處理多個客戶端。 – Dogbert
@Dogbert:我更新我的問題以舉例說明「在某個時間點」可能是什麼。如果在我更新後它仍然有效,您是否介意並給出一個簡短的答案示例?謝謝你的幫助! – Pascal