【发布时间】:2019-11-04 03:25:42
【问题描述】:
首先,完全缺乏 Cowboy 的文档,尤其是 Websockets,但总的来说,一旦解密,它就可以很好地使用。然后将这些信息从 Erlang 获取到 Elixir 是另一个步骤。感谢this post by 7stud,我能够获得一个功能正常的 websocket 用于测试目的,但我无法让它同时收听和选择性地发送消息。我认为这是因为接收阻塞了需要发送的线程,这本质上与 websocket 连接相关联,因此它在等待接收时无法发送。也许这种理解是有缺陷的。我很想得到纠正。我尝试生成无济于事,这就是为什么我认为接收阻塞了 websocket 线程。
def ws do
localhost = 'localhost'
path = '/ws/app/1'
port = 5000
{:ok, _} = :application.ensure_all_started(:gun)
connect_opts = %{
connect_timeout: :timer.minutes(1),
retry: 10,
retry_timeout: 100
}
{:ok, conn_pid} = :gun.open(localhost, port, connect_opts)
IO.inspect(conn_pid, label: "conn_pid")
{:ok, protocol} = :gun.await_up(conn_pid)
IO.inspect(protocol, label: "protocol")
# Set custom header with cookie for device id
stream_ref = :gun.ws_upgrade(conn_pid, path, [{"cookie", "device_id=1235"}])
IO.inspect(stream_ref, label: "stream_ref")
receive do
{:gun_upgrade, ^conn_pid, ^stream_ref, ["websocket"], headers} ->
upgrade_success(conn_pid, headers, stream_ref)
{:gun_response, ^conn_pid, _, _, status, headers} ->
exit({:ws_upgrade_failed, status, headers})
{:gun_error, _conn_pid, _stream_ref, reason} ->
exit({:ws_upgrade_failed, reason})
whatever ->
IO.inspect(whatever, label: "Whatever")
# More clauses here as needed.
after 5000 ->
IO.puts "Took too long!"
:erlang.exit("barf!")
end
:ok
end
def upgrade_success(conn_pid, headers, stream_ref) do
IO.puts("Upgraded #{inspect(conn_pid)}. Success!\nHeaders:\n#{inspect(headers)}\n")
IO.inspect(self(), label: "upgrade self")
# This one runs and message is received
run_test(conn_pid)
# This should spawn and therefore not block
listen(conn_pid, stream_ref)
# This never runs
run_test(conn_pid)
end
def listen(conn_pid, stream_ref) do
spawn receive_messages(conn_pid, stream_ref)
end
def receive_messages(conn_pid, stream_ref) do
IO.inspect conn_pid, label: "conn_pid!"
IO.inspect stream_ref, label: "stream_ref!"
IO.inspect(self(), label: "self pid")
receive do
{:gun_ws, ^conn_pid, ^stream_ref, {:text, msg} } ->
IO.inspect(msg, label: "Message from websocket server:")
other_messages ->
IO.inspect(other_messages, label: "Other messages")
after 5000 ->
IO.puts "Receive timed out"
end
receive_messages(conn_pid, stream_ref)
end
def send_message(message, conn_pid) do
:gun.ws_send(conn_pid, {:text, message})
end
def run_test(conn_pid) do
IO.puts "Running test"
message = "{\"type\":\"init\",\"body\":{\"device_id\":1234}}"
send_message(message, conn_pid)
end
def stop(conn_pid) do
:gun.shutdown(conn_pid)
end
【问题讨论】:
-
我认为这是因为接收阻塞了需要发送的线程,这本质上与 websocket 连接相关联,因此它在等待接收时无法发送。也许这种理解是有缺陷的。 -- 是的,我认为它一定是有缺陷的,因为这里所说的:ninenines.eu/docs/en/cowboy/2.1/guide/ws_protocol。 使用Websocket,客户端和服务器都可以随时发送帧,没有任何限制。
-
我能够让一个正常运行的 websocket 用于测试目的,但我无法让它同时监听和发送消息。 -- @ 是什么意思987654325@那句话指的是什么?服务器还是客户端?
-
@7stud 我已经有一个服务器正在运行。现在我正在尝试获得一个有效的客户。 “服务器”是指等待从各种客户端接收 websocket 连接的程序。
-
对于任何感兴趣的人我已经完成了这个,如果你正在寻找一个更完整的例子,你可以看看这个 repo。 github.com/GamgeeNL/websocket-client
标签: websocket erlang elixir client