作为 Cowboy 客户端,您如何使用 Gun?

2023-11-26

我跟着入门说明对于 Cowboy,我让 Cowboy 在端口 8080 上运行并侦听,然后我得到了Hello Erlang!当我进入时的回应http://localhost:8080在我的浏览器中。现在,如何使用 Gun 连接到 Cowboy?

我读了Gun docs,它说添加“Gun 作为 erlang.mk 依赖项”。所以我下载了erlang.mk:

~/erlang_programs/my_gun$ curl -O https://erlang.mk/erlang.mk

并遵循Erlang.mk 用户指南,我创建了一个应用程序:

~/erlang_programs/my_gun$ gmake -f erlang.mk bootstrap

然后我将 Gun 作为依赖项添加到 Makefile 中:

PROJECT = my_gun
PROJECT_DESCRIPTION = New project
PROJECT_VERSION = 0.1.0

DEPS = gun

include erlang.mk

然后我编译了:

~/erlang_programs/my_gun$ gmake
gmake[1]: Entering directory '/Users/7stud/erlang_programs/my_gun/deps/gun'
gmake[2]: Entering directory '/Users/7stud/erlang_programs/my_gun/deps/cowlib'
 ERLC   cow_cookie.erl cow_date.erl cow_hpack.erl cow_http.erl cow_http2.erl cow_http_hd.erl cow_http_te.erl cow_mimetypes.erl cow_multipart.erl cow_qs.erl cow_spdy.erl cow_sse.erl cow_uri.erl cow_ws.erl
 APP    cowlib
gmake[2]: Leaving directory '/Users/7stud/erlang_programs/my_gun/deps/cowlib'
gmake[2]: Entering directory '/Users/7stud/erlang_programs/my_gun/deps/ranch'
 DEPEND ranch.d
 ERLC   ranch.erl ranch_acceptor.erl ranch_acceptors_sup.erl ranch_app.erl ranch_conns_sup.erl ranch_listener_sup.erl ranch_protocol.erl ranch_server.erl ranch_ssl.erl ranch_sup.erl ranch_tcp.erl ranch_transport.erl
 APP    ranch
gmake[2]: Leaving directory '/Users/7stud/erlang_programs/my_gun/deps/ranch'
 DEPEND gun.d
 ERLC   gun.erl gun_app.erl gun_content_handler.erl gun_data.erl gun_http.erl gun_http2.erl gun_spdy.erl gun_sse.erl gun_sup.erl gun_ws.erl gun_ws_handler.erl
 APP    gun
 GEN    rebar.config
gmake[1]: Leaving directory '/Users/7stud/erlang_programs/my_gun/deps/gun'
 DEPEND my_gun.d
 ERLC   my_gun_app.erl my_gun_sup.erl
 APP    my_gun
 GEN    /Users/7stud/erlang_programs/my_gun/.erlang.mk/relx
===> Starting relx build process ...
===> Resolving OTP Applications from directories:
          /Users/7stud/erlang_programs/my_gun/ebin
          /Users/7stud/erlang_programs/my_gun/deps
          /Users/7stud/.evm/erlang_versions/otp_src_19.2/lib/erlang/lib
          /Users/7stud/erlang_programs/my_gun/apps
===> Resolved my_gun_release-1
===> rendering builtin_hook_status hook to "/Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/bin/hooks/builtin/status"
===> Including Erts from /Users/7stud/.evm/erlang_versions/otp_src_19.2/lib/erlang
===> release successfully created!
===> tarball /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/my_gun_release-1.tar.gz successfully created!

但是当我切换到 erlang shell 并尝试启动 Gun 时,出现错误:

~/erlang_programs/my_gun$ erl
Erlang/OTP 19 [erts-8.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] 

Eshell V8.2  (abort with ^G)

1> application:ensure_all_started(gun).
{error,{gun,{"no such file or directory","gun.app"}}}

有人可以发布一个简单的示例来说明如何使用 Gun(或任何其他支持 websocket 的 http 客户端)连接到 Cowboy?


好吧,我取得了一些进展。我删除了my_gun目录,重新创建了该目录,重新下载了erlang.mk,并创建了释放与以下command:

~/erlang_programs/my_gun$ gmake -f erlang.mk bootstrap-lib bootstrap-rel

然后我将 Gun 依赖项添加到 Makefile 中(如上所述)。然后我做了:

 ~/erlang_programs/my_gun$ gmake run

如果代码中没有错误,则会启动 erlang shell。在 erlang shell 中,我输入了以下代码(请参阅tip下面以避免必须在 shell 中键入所有代码):

([email protected])1> application:ensure_all_started(gun).
{ok,[]}

([email protected])2> {ok, ConnPid} = gun:open("localhost", 8080).  

=PROGRESS REPORT==== 10-Jul-2017::05:21:58 ===
          supervisor: {local,inet_gethost_native_sup}
             started: [{pid,<0.366.0>},{mfa,{inet_gethost_native,init,[[]]}}]
{ok,<0.364.0>}

=PROGRESS REPORT==== 10-Jul-2017::05:21:58 ===
          supervisor: {local,kernel_safe_sup}
             started: [{pid,<0.365.0>},
                       {id,inet_gethost_native_sup},
                       {mfargs,{inet_gethost_native,start_link,[]}},
                       {restart_type,temporary},
                       {shutdown,1000},
                       {child_type,worker}]

([email protected])3> {ok, Protocol} = gun:await_up(ConnPid).
{ok,http}

([email protected])4> gun:ws_upgrade(ConnPid, "/websocket").
#Ref<0.0.3.244>

([email protected])5> receive                                          
([email protected])5> {gun_ws_upgrade, ConnPid, ok, Headers} ->        
([email protected])5> upgrade_success(ConnPid);
([email protected])5> {gun_response, ConnPid, _, _, Status, Headers} ->
([email protected])5> exit({ws_upgrade_failed, Status, Headers});
([email protected])5> {gun_error, ConnPid, StreamRef, Reason} ->
([email protected])5> exit({ws_upgrade_failed, Reason})
([email protected])5> after 1000 ->
([email protected])5> exit(timeout)
([email protected])5> end.

=CRASH REPORT==== 10-Jul-2017::05:25:17 ===
  crasher:
    initial call: gun:proc_lib_hack/5
    pid: <0.364.0>
    registered_name: []
    exception exit: {{owner_gone,normal},
                     [{gun,loop,1,[{file,"src/gun.erl"},{line,706}]},
                      {gun,proc_lib_hack,5,[{file,"src/gun.erl"},{line,535}]},
                      {proc_lib,init_p_do_apply,3,
                                [{file,"proc_lib.erl"},{line,247}]}]}
      in function  gun:proc_lib_hack/5 (src/gun.erl, line 540)
    ancestors: [gun_sup,<0.343.0>]
    messages: []
    links: [<0.344.0>]
    dictionary: []
    trap_exit: false
    status: running
    heap_size: 2586
    stack_size: 27
    reductions: 10857
  neighbours:

=SUPERVISOR REPORT==== 10-Jul-2017::05:25:17 ===
     Supervisor: {local,gun_sup}
     Context:    child_terminated
     Reason:     {{owner_gone,normal},
                  [{gun,loop,1,[{file,"src/gun.erl"},{line,706}]},
                   {gun,proc_lib_hack,5,[{file,"src/gun.erl"},{line,535}]},
                   {proc_lib,init_p_do_apply,3,
                             [{file,"proc_lib.erl"},{line,247}]}]}
     Offender:   [{pid,<0.364.0>},
                  {id,gun},
                  {mfargs,{gun,start_link,undefined}},
                  {restart_type,temporary},
                  {shutdown,5000},
                  {child_type,worker}]

** exception exit: {ws_upgrade_failed,404,
                                      [{<<"content-length">>,<<"0">>},
                                       {<<"date">>,
                                        <<"Mon, 10 Jul 2017 11:22:38 GMT">>},
                                       {<<"server">>,<<"Cowboy">>}]}
([email protected])6> 

现在,我收到 404 错误。牛仔正在奔跑,当我进入时http://localhost:8080 in my browser,我看到一条回复消息。为什么 Gun 给我一个 404 错误?


接下来我尝试使用中的说明Gun docs发出 GET 请求:

StreamRef = gun:get(ConnPid, "/").

case gun:await(ConnPid, StreamRef) of
    {response, fin, Status, Headers} ->
        no_data;
    {response, nofin, Status, Headers} ->
        {ok, Body} = gun:await_body(ConnPid, StreamRef),
        io:format("~s~n", [Body])
end.

那是成功的:

=PROGRESS REPORT==== 10-Jul-2017::06:36:14 ===
          supervisor: {local,inet_gethost_native_sup}
             started: [{pid,<0.367.0>},{mfa,{inet_gethost_native,init,[[]]}}]

=PROGRESS REPORT==== 10-Jul-2017::06:36:14 ===
          supervisor: {local,kernel_safe_sup}
             started: [{pid,<0.366.0>},
                       {id,inet_gethost_native_sup},
                       {mfargs,{inet_gethost_native,start_link,[]}},
                       {restart_type,temporary},
                       {shutdown,1000},
                       {child_type,worker}]
Hello Erlang!
ok
([email protected])2> 

该响应意味着我能够使用 Gun 与 Cowboy 服务器交互 - 但我想使用 websockets。有什么想法我做错了吗?


tip:

为了避免在枪壳中输入所有代码,我创建了该文件~/erlang_programs/my_gun/src/my.erl:

-module(my).
-compile(export_all).

get() ->
    {ok, _} = application:ensure_all_started(gun),
    {ok, ConnPid} = gun:open("localhost", 8080),
    {ok, _Protocol} = gun:await_up(ConnPid),

    StreamRef = gun:get(ConnPid, "/"),

    case gun:await(ConnPid, StreamRef) of
        {response, fin, _Status, _Headers} ->
            no_data;
        {response, nofin, _Status, _Headers} ->
            {ok, Body} = gun:await_body(ConnPid, StreamRef),
            io:format("~s~n", [Body])
    end.

ws() ->

    {ok, _} = application:ensure_all_started(gun),
    {ok, ConnPid} = gun:open("localhost", 8080),
    {ok, _Protocol} = gun:await_up(ConnPid),

    gun:ws_upgrade(ConnPid, "/websocket"),

    receive
    {gun_ws_upgrade, ConnPid, ok, Headers} ->
            upgrade_success(ConnPid, Headers);
    {gun_response, ConnPid, _, _, Status, Headers} ->
            exit({ws_upgrade_failed, Status, Headers});
    {gun_error, _ConnPid, _StreamRef, Reason} ->
            exit({ws_upgrade_failed, Reason})
    %% More clauses here as needed.
    after 1000 ->
        exit(timeout)
    end,

    gun:shutdown(ConnPid).


upgrade_success(ConnPid, Headers) ->
    io:format("Upgraded ~w. Success!~nHeaders:~n~p~n", 
              [ConnPid, Headers]).

然后 make(或 gmake)命令:

 ~/erlang_programs/my_gun$ gmake run

将编译所有内容src/目录并提醒您任何错误。一旦枪弹成功发射响应gmake run,您可以例如执行以下操作:

([email protected])1> my:get().

=PROGRESS REPORT==== 10-Jul-2017::06:36:14 ===
          supervisor: {local,inet_gethost_native_sup}
             started: [{pid,<0.367.0>},{mfa,{inet_gethost_native,init,[[]]}}]

=PROGRESS REPORT==== 10-Jul-2017::06:36:14 ===
          supervisor: {local,kernel_safe_sup}
             started: [{pid,<0.366.0>},
                       {id,inet_gethost_native_sup},
                       {mfargs,{inet_gethost_native,start_link,[]}},
                       {restart_type,temporary},
                       {shutdown,1000},
                       {child_type,worker}]
Hello Erlang!
ok
([email protected])2> 

对评论的回应:

既然你得到了 404,我猜你没有 websocket 处理程序 在牛仔路线中定义。

你是对的。我只在《牛仔入门指南》中显示了处理程序。现在,我已向牛仔添加了 websocket 设置代码和 websocket 处理程序。我现在有路线:

你好_erlang_app.erl:

-module(hello_erlang_app).
-behaviour(application).

-export([start/2]).
-export([stop/1]).

start(_Type, _Args) ->
    Dispatch = cowboy_router:compile([
        {'_', [{"/", hello_handler, []}] },
        {'_', [{"/websocket", myws_handler, []}] }
    ]),

    {ok, _} = cowboy:start_clear(my_http_listener,
        [{port, 8080}],
        #{env => #{dispatch => Dispatch} }
    ),

    hello_erlang_sup:start_link().

stop(_State) ->
    ok.

这是我的处理程序:

-module(myws_handler).
-compile(export_all).

init(Req, State) ->
    {cowboy_websocket, Req, State}.  %Perform websocket setup

websocket_handle({text, Msg}, State) ->
    {
     reply, 
     {text, <<"Server received: ", Msg/binary>>, State}  %%Error in format here, too!
    };
websocket_handle(_Data, State) ->
    {ok, State}.

但是执行的时候还是出现404错误my:ws()在枪壳中:

-module(my).
-compile(export_all).

get() ->
    {ok, _} = application:ensure_all_started(gun),
    {ok, ConnPid} = gun:open("localhost", 8080),
    {ok, _Protocol} = gun:await_up(ConnPid),

    StreamRef = gun:get(ConnPid, "/"),

    case gun:await(ConnPid, StreamRef) of
        {response, fin, _Status, _Headers} ->
            no_data;
        {response, nofin, _Status, _Headers} ->
            {ok, Body} = gun:await_body(ConnPid, StreamRef),
            io:format("~s~n", [Body])
    end.

ws() ->

    {ok, _} = application:ensure_all_started(gun),
    {ok, ConnPid} = gun:open("localhost", 8080),
    {ok, _Protocol} = gun:await_up(ConnPid),

    gun:ws_upgrade(ConnPid, "/websocket"),

    receive
        {gun_ws_upgrade, ConnPid, ok, Headers} ->
            upgrade_success(ConnPid, Headers);
        {gun_response, ConnPid, _, _, Status, Headers} ->
            exit({ws_upgrade_failed, Status, Headers});
        {gun_error, _ConnPid, _StreamRef, Reason} ->
            exit({ws_upgrade_failed, Reason})
    %% More clauses here as needed.
    after 1000 ->
        exit(timeout)
    end,

    gun:shutdown(ConnPid).


upgrade_success(ConnPid, Headers) ->
    io:format("Upgraded ~w. Success!~nHeaders:~n~w~n", 
              [ConnPid, Headers]).

这是输出:

~/erlang_programs/my_gun$ gmake run
gmake[1]: Entering directory '/Users/7stud/erlang_programs/my_gun/deps/gun'
gmake[2]: Entering directory '/Users/7stud/erlang_programs/my_gun/deps/cowlib'
gmake[2]: Leaving directory '/Users/7stud/erlang_programs/my_gun/deps/cowlib'
gmake[2]: Entering directory '/Users/7stud/erlang_programs/my_gun/deps/ranch'
gmake[2]: Leaving directory '/Users/7stud/erlang_programs/my_gun/deps/ranch'
 GEN    rebar.config
gmake[1]: Leaving directory '/Users/7stud/erlang_programs/my_gun/deps/gun'
 DEPEND my_gun.d
 ERLC   my.erl
 APP    my_gun
===> Starting relx build process ...
===> Resolving OTP Applications from directories:
          /Users/7stud/erlang_programs/my_gun/ebin
          /Users/7stud/erlang_programs/my_gun/deps
          /Users/7stud/.evm/erlang_versions/otp_src_19.2/lib/erlang/lib
          /Users/7stud/erlang_programs/my_gun/apps
          /Users/7stud/erlang_programs/my_gun/_rel
===> Resolved my_gun_release-1
===> rendering builtin_hook_status hook to "/Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/bin/hooks/builtin/status"
===> Including Erts from /Users/7stud/.evm/erlang_versions/otp_src_19.2/lib/erlang
===> release successfully created!
===> tarball /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/my_gun_release-1.tar.gz successfully created!
Exec: /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/erts-8.2/bin/erlexec -boot /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/releases/1/my_gun_release -mode embedded -boot_var ERTS_LIB_DIR /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/lib -config /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/releases/1/sys.config -args_file /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/releases/1/vm.args -pa -- console
Root: /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release
/Users/7stud/erlang_programs/my_gun/_rel/my_gun_release
heart_beat_kill_pid = 32843
Erlang/OTP 19 [erts-8.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]


=PROGRESS REPORT==== 10-Jul-2017::16:26:05 ===
          supervisor: {local,sasl_safe_sup}
             started: [{pid,<0.353.0>},
                       {id,alarm_handler},
                       {mfargs,{alarm_handler,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]

=PROGRESS REPORT==== 10-Jul-2017::16:26:05 ===
          supervisor: {local,sasl_sup}
             started: [{pid,<0.352.0>},
                       {id,sasl_safe_sup},
                       {mfargs,
                           {supervisor,start_link,
                               [{local,sasl_safe_sup},sasl,safe]}},
                       {restart_type,permanent},
                       {shutdown,infinity},
                       {child_type,supervisor}]

=PROGRESS REPORT==== 10-Jul-2017::16:26:05 ===
          supervisor: {local,sasl_sup}
             started: [{pid,<0.354.0>},
                       {id,release_handler},
                       {mfargs,{release_handler,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]

=PROGRESS REPORT==== 10-Jul-2017::16:26:05 ===
         application: sasl
          started_at: '[email protected]'

=PROGRESS REPORT==== 10-Jul-2017::16:26:05 ===
          supervisor: {local,runtime_tools_sup}
             started: [{pid,<0.360.0>},
                       {id,ttb_autostart},
                       {mfargs,{ttb_autostart,start_link,[]}},
                       {restart_type,temporary},
                       {shutdown,3000},
                       {child_type,worker}]

=PROGRESS REPORT==== 10-Jul-2017::16:26:05 ===
         application: runtime_tools
          started_at: '[email protected]'
Eshell V8.2  (abort with ^G)

([email protected])1> my:ws().

=PROGRESS REPORT==== 10-Jul-2017::16:26:08 ===
          supervisor: {local,inet_gethost_native_sup}
             started: [{pid,<0.367.0>},{mfa,{inet_gethost_native,init,[[]]}}]

=PROGRESS REPORT==== 10-Jul-2017::16:26:08 ===
          supervisor: {local,kernel_safe_sup}
             started: [{pid,<0.366.0>},
                       {id,inet_gethost_native_sup},
                       {mfargs,{inet_gethost_native,start_link,[]}},
                       {restart_type,temporary},
                       {shutdown,1000},
                       {child_type,worker}]

=CRASH REPORT==== 10-Jul-2017::16:26:08 ===
  crasher:
    initial call: gun:proc_lib_hack/5
    pid: <0.365.0>
    registered_name: []
    exception exit: {{owner_gone,normal},
                     [{gun,loop,1,[{file,"src/gun.erl"},{line,706}]},
                      {gun,proc_lib_hack,5,[{file,"src/gun.erl"},{line,535}]},
                      {proc_lib,init_p_do_apply,3,
                                [{file,"proc_lib.erl"},{line,247}]}]}
      in function  gun:proc_lib_hack/5 (src/gun.erl, line 540)
    ancestors: [gun_sup,<0.345.0>]
    messages: []
    links: [<0.346.0>]
    dictionary: []
    trap_exit: false
    status: running
    heap_size: 610
    stack_size: 27
    reductions: 1042
  neighbours:

=SUPERVISOR REPORT==== 10-Jul-2017::16:26:08 ===
     Supervisor: {local,gun_sup}
     Context:    child_terminated
     Reason:     {{owner_gone,normal},
                  [{gun,loop,1,[{file,"src/gun.erl"},{line,706}]},
                   {gun,proc_lib_hack,5,[{file,"src/gun.erl"},{line,535}]},
                   {proc_lib,init_p_do_apply,3,
                             [{file,"proc_lib.erl"},{line,247}]}]}
     Offender:   [{pid,<0.365.0>},
                  {id,gun},
                  {mfargs,{gun,start_link,undefined}},
                  {restart_type,temporary},
                  {shutdown,5000},
                  {child_type,worker}]

** exception exit: {ws_upgrade_failed,404,
                                      [{<<"content-length">>,<<"0">>},
                                       {<<"date">>,
                                        <<"Mon, 10 Jul 2017 22:26:08 GMT">>},
                                       {<<"server">>,<<"Cowboy">>}]}
     in function  my:ws/0 (src/my.erl, line 30)

([email protected])2> 

我保存了所有文件并重新启动了牛仔和枪,因此我对代码所做的更改正在执行,但我仍然收到 404 错误。


我将我的路线的格式与在注释中spawn_think链接到的示例中的路线进行了比较,我的格式是错误的。这是我现在所拥有的:

-module(hello_erlang_app).
-behaviour(application).

-export([start/2]).
-export([stop/1]).

start(_Type, _Args) ->
    Dispatch = cowboy_router:compile([
        {'_', [
               {"/", hello_handler, []},
               {"/websocket", myws_handler, []} 
        ]}
    ]),

    {ok, _} = cowboy:start_clear(my_http_listener,
        [{port, 8080}],
        #{env => #{dispatch => Dispatch} }
    ),

    hello_erlang_sup:start_link().

stop(_State) ->
    ok.

在我的枪客户端中调整 io:format() 语句中的控制序列之一后:

-module(my).
-compile(export_all).

get() ->
    ...

ws() ->
    ...

upgrade_success(ConnPid, Headers) ->
    io:format("Upgraded ~w. Success!~nHeaders:~n~p~n",   %% <*** CHANGED ~w to ~p 
              [ConnPid, Headers]).

这是输出:

~/erlang_programs/my_gun$ gmake run
gmake[1]: Entering directory '/Users/7stud/erlang_programs/my_gun/deps/gun'
gmake[2]: Entering directory '/Users/7stud/erlang_programs/my_gun/deps/cowlib'
gmake[2]: Leaving directory '/Users/7stud/erlang_programs/my_gun/deps/cowlib'
gmake[2]: Entering directory '/Users/7stud/erlang_programs/my_gun/deps/ranch'
gmake[2]: Leaving directory '/Users/7stud/erlang_programs/my_gun/deps/ranch'
 GEN    rebar.config
gmake[1]: Leaving directory '/Users/7stud/erlang_programs/my_gun/deps/gun'
 DEPEND my_gun.d
 ERLC   my.erl
 APP    my_gun
===> Starting relx build process ...
===> Resolving OTP Applications from directories:
          /Users/7stud/erlang_programs/my_gun/ebin
          /Users/7stud/erlang_programs/my_gun/deps
          /Users/7stud/.evm/erlang_versions/otp_src_19.2/lib/erlang/lib
          /Users/7stud/erlang_programs/my_gun/apps
          /Users/7stud/erlang_programs/my_gun/_rel
===> Resolved my_gun_release-1
===> rendering builtin_hook_status hook to "/Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/bin/hooks/builtin/status"
===> Including Erts from /Users/7stud/.evm/erlang_versions/otp_src_19.2/lib/erlang
===> release successfully created!
===> tarball /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/my_gun_release-1.tar.gz successfully created!
Exec: /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/erts-8.2/bin/erlexec -boot /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/releases/1/my_gun_release -mode embedded -boot_var ERTS_LIB_DIR /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/lib -config /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/releases/1/sys.config -args_file /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/releases/1/vm.args -pa -- console
Root: /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release
/Users/7stud/erlang_programs/my_gun/_rel/my_gun_release
heart_beat_kill_pid = 34141
Erlang/OTP 19 [erts-8.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]


=PROGRESS REPORT==== 10-Jul-2017::16:50:53 ===
          supervisor: {local,sasl_safe_sup}
             started: [{pid,<0.353.0>},
                       {id,alarm_handler},
                       {mfargs,{alarm_handler,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]

=PROGRESS REPORT==== 10-Jul-2017::16:50:53 ===
          supervisor: {local,sasl_sup}
             started: [{pid,<0.352.0>},
                       {id,sasl_safe_sup},
                       {mfargs,
                           {supervisor,start_link,
                               [{local,sasl_safe_sup},sasl,safe]}},
                       {restart_type,permanent},
                       {shutdown,infinity},
                       {child_type,supervisor}]

=PROGRESS REPORT==== 10-Jul-2017::16:50:53 ===
          supervisor: {local,sasl_sup}
             started: [{pid,<0.354.0>},
                       {id,release_handler},
                       {mfargs,{release_handler,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]

=PROGRESS REPORT==== 10-Jul-2017::16:50:53 ===
         application: sasl
          started_at: '[email protected]'

=PROGRESS REPORT==== 10-Jul-2017::16:50:53 ===
          supervisor: {local,runtime_tools_sup}
             started: [{pid,<0.360.0>},
                       {id,ttb_autostart},
                       {mfargs,{ttb_autostart,start_link,[]}},
                       {restart_type,temporary},
                       {shutdown,3000},
                       {child_type,worker}]

=PROGRESS REPORT==== 10-Jul-2017::16:50:53 ===
         application: runtime_tools
          started_at: '[email protected]'
Eshell V8.2  (abort with ^G)
([email protected])1> my:ws().

=PROGRESS REPORT==== 10-Jul-2017::16:50:57 ===
          supervisor: {local,inet_gethost_native_sup}
             started: [{pid,<0.367.0>},{mfa,{inet_gethost_native,init,[[]]}}]

=PROGRESS REPORT==== 10-Jul-2017::16:50:57 ===
          supervisor: {local,kernel_safe_sup}
             started: [{pid,<0.366.0>},
                       {id,inet_gethost_native_sup},
                       {mfargs,{inet_gethost_native,start_link,[]}},
                       {restart_type,temporary},
                       {shutdown,1000},
                       {child_type,worker}]
Upgraded <0.365.0>. Success!
Headers:
[{<<"connection">>,<<"Upgrade">>},
 {<<"date">>,<<"Mon, 10 Jul 2017 22:50:56 GMT">>},
 {<<"sec-websocket-accept">>,<<"S1w7rWXToZefi/NOEcDAEDb4yEU=">>},
 {<<"server">>,<<"Cowboy">>},
 {<<"upgrade">>,<<"websocket">>}]
ok
([email protected])2> 

我已经达到了论坛的文本限制,因此请参阅我的答案,了解我实际上如何使用 Websocket 发送和接收数据。


评论讨论中的问题/建议摘要

  1. 为了运行你的 Erlang 应用程序(在本例中包括 Gun 作为依赖项),你需要有 shell 可以发现的 Beam 和 .app 文件的路径。使用 erlang.mk 时,最简单的方法是使用以下命令运行版本make run

  2. 在 Cowboy 方面,要正确处理 Websocket,您需要在牛仔路由中定义一个处理程序。请参阅示例牛仔 Websocket 示例

也可以看看枪支使用指南有关在 Gun 中处理 Websocket 的更多详细信息

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

作为 Cowboy 客户端,您如何使用 Gun? 的相关文章

  • 接收缓冲区的限制

    我通过以下方式与客户端建立了连接 gen tcp listen 1234 binary packet 0 reuseaddr true active false recbuf 2048 此代码执行消息处理 loop Socket gt in
  • 在 Erlang 中编写和编译自定义行为

    我试图在 Erlang 中编写并编译自定义行为 我找不到任何关于如何编译此行为的明确文档 module bla export start link 0 behaviour info 1 behaviour info callbacks gt
  • 具有大状态的 erlang gen_server

    我有一个包含数千个条目的特里树 用元组和列表实现 我想支持并发读取 数据的内存占用量在 10 20 MB 范围内 特里树被构建一次 之后只读 维护状态并为客户端提供并发访问的推荐方法是什么 这是我尝试过的 1 创建一个gen server
  • erlang中如何将中缀转换为后缀?

    我刚刚遇到这个帖子 https stackoverflow com questions 4621151 the shortest way to convert infix expressions to postfix rpn in c 相当
  • 在 Windows 上编译 Erlang 代码

    我安装了 Erlang 13B 并尝试按照教程进行操作 每次我到达c tut 我得到一个错误而不是 ok tut 所以看起来没有安装任何模块 有人能指出我正确的方向吗 我尝试过 Emacs 但我真的不知道如何使用它 甚至还没有接近让 Erl
  • 为什么在 Erlang 中使用 OTP?

    正如问题所说 使用 Erlang 进行开发时 使用 OTP 设计原则会带来什么好处 我正在开发一个仅接收命令并发送响应的服务器 正如 Jonas 所说 OTP 是一组久经考验的设计元素和习惯用法 用于创建容错系统以及其他功能 例如灵活性 实
  • 随机排列列表中的元素(随机重新排列列表元素)

    我的程序的一部分要求我能够随机洗牌列表元素 我需要一个函数 当我给它一个列表时 它会伪随机地重新排列列表中的元素 安排的改变Must每次通话时都可以看到相同的列表 我的实现似乎工作得很好 但我觉得它相当长 并且正在增加我的代码库 而且 我有
  • Erlang 生成问题

    我在 erlang 中遇到了 spawn 问题 似乎进程在一段时间后就死掉了 这是简单的代码 module simple export server 1 client 1 owner 1 spawn n 2 start 1 main 1 s
  • 使用字符串将 Erlang 映射编码为 JSON 以便通过 Javascript 进行解析?

    我正在尝试使用 Erlang 地图 例如 breakfast gt leftovers 并编码为 JSON 映射 例如 我尝试使用 jiffy 转换列表 email protected cdn cgi l email protection
  • Node.js 或 Erlang

    当谈到它们可以处理的并发级别时 我真的很喜欢这些工具 Erlang OTP 看起来是更稳定的解决方案 但需要更多的学习和深入研究函数式语言范例 看起来 Erlang OTP 在多核 CPU 方面做得更好 如果我错了 请纠正我 但我应该选择哪
  • Erlang 参与者与 OOP 对象有何不同?

    假设我有一个 Erlang actor 定义如下 counter Num gt receive From increment gt From self new value Num 1 counter Num 1 end 同样 我有一个 Ru
  • Erl 无法连接到本地 EPMD。为什么?

    Erlang R14B04 erts 5 8 5 source 64 bit rq 1 async threads 0 kernel poll false Eshell V5 8 5 abort with G root ip 10 101
  • 如何修改erlang中的记录?

    我需要修改操作记录中的值 place 和 other place op action walk from place to other place preconds at place me on floor me other place p
  • Mnesia:如何同时锁定多行,以便我可以写入/读取一组“一致”的记录

    我多么希望我一开始就能表达我的问题 取一个包含 26 个键 a z 的表 并让它们具有整数值 创建一个流程 哎哟 一遍又一遍地做两件事 在一笔交易中 写入随机值a b and c使得这些值always总和为 10 在另一个事务中 读取值a
  • 如何将列表转换为元组列表?

    我想转换 z z a z z a a z to z 2 a 1 z 2 a 2 z 1 我该怎么做 所以 我需要累积以前的值 它的计数器和元组列表 我已创建记录 record acc previous counter tuples 重新定义
  • 如何限制Erlang VM(BEAM)使用的核心数量?

    我正在具有 2 个四核 Xeon E5520 2 2GHz 24 0GB RAM 和 Erlang R15B02 启用 SMP 的节点上运行实验 我想知道是否可以限制Erlang VM使用的核心数量 以便我可以暂时禁用一些核心并逐步增加数量
  • Erlang:如何将原子转换为字符串?

    我想从原子转换为字符串 Input hello world Output hello world 我该如何实现这一目标 Use atom to list http erlang org doc man erlang html atom to
  • 在 digraph_utils:is_acirclic/1 返回 false 后查找循环或循环

    我怎样才能 有效地 在Erlang有向图中找到循环或循环digraph utils is acyclic 1返回假 EDIT is acyclic is 定义为 https github com erlang otp blob maint
  • Erlang 中的接受器池和负载平衡?

    From http www erlang org doc man gen tcp html accept 1 http www erlang org doc man gen tcp html accept 1 值得注意的是 accept 调
  • Erlang 中的变量

    我有一个非常简单的 Erlang 程序 module test export start 0 Code Z00887 start gt io fwrite Code 我有以下两个错误 c erl6 1 dev test erl 4 之前的语

随机推荐

  • GDB 中的格式化打印

    我想做printf风格印刷来自GDB 例如 我想打印一个变量值 但用一些文本来描述它是什么 可以吗 如果可以的话 能举个例子吗 你可以非常多地使用printf in gdb如下 gdb printf s x Hello world gdb
  • Laravel 样式表和 javascript 不会加载非基本路由

    好吧 我知道这是一个非常基本的问题 但我无法弄清楚 这是一个关于 Laravel 的问题 基本上 我将样式表嵌入到我的默认布局视图中 我目前只是使用常规 css 来链接它们 例如 当我处于单级路线时 例如 about 但是当我深入时停止工作
  • 类 C 语言中的返回类型多态性

    为什么我们没有看到类似 C 的语言允许在返回类型中具有多态性的可调用对象 我可以看到附加类型推断将成为一个障碍 但我们有很多语言具有成熟的类型推理系统 适用于不同级别的 工作 Edit 通过返回类型多态性 我的意思是仅在返回类型中重载函数签
  • 使用 TextDecoder/TextEncoder 将 ArrayBuffer 转换为 String,然后返回 ArrayBuffer,返回不同的结果

    我有一个 ArrayBuffer 它是通过使用 Frida 读取内存而返回的 我将 ArrayBuffer 转换为字符串 然后使用 TextDecoder 和 TextEncoder 返回 ArrayBuffer 但结果在此过程中发生了变化
  • Java 中保存连接字符串参数的配置文件

    我有 ASP Net 背景 我现在正在编写一个Java 程序 将数据从DB2 数据库导入到Oracle 数据库中 我已经完成了导入此数据的基本功能 我遇到的问题是 我将所有连接属性都编码到了 Java 程序本身中 是否有任何 最佳实践 方法
  • CSS:如何使光标成为输入文件上的指针?

    当鼠标悬停时 如何使光标成为输入文件或输入文本上的指针 我尝试过 但当然行不通
  • password_hash 的盐存储在哪里?

    根据 相对 新的 PHP 文档 The 密码哈希值函数使用随机盐 我们不应该担心 O O 所以如果我理解正确 盐必须存储在某个地方 否则用户在注册网站后将无法登录 不同的盐 gt 不同的哈希值 该函数文档没有告诉任何有关与数据库交互的信息
  • 是否有基于其他运算符自动提供的 C++ 运算符重载? [复制]

    这个问题在这里已经有答案了 假设我正在写一个int包装器并需要提供每个操作符重载 作者是否必须列出每一项 还是可以根据作者提供的内容自动生成任何一项 编译器是否可以从现有的运算符中推断出任何新的自动定义运算符 如果我定义operator 它
  • 在 iOS 7 中强制横向和自动旋转

    我的应用程序应该只是横向的 在构建时我没有遇到任何问题iOS 6和更早的时候 现在与iOS 7 它根本不会旋转 在我的应用程序设置中 我将其设置为仅横向左 右 在我的视图控制器中 我使用以下内容 NSUInteger supportedIn
  • 如何在 web.config 文件中更改我的 asp.net 网站的默认时区

    我正在尝试更改我的 asp net 网站的默认时区 我尝试了以下代码 但它不起作用
  • 如何为 List 实现 Parcelable

    我正在尝试在我的可打包中传递一个列表 public class MetaDados implements Parcelable private List
  • 哈希表与 C++ 中的 STL 映射

    我正在尝试学习 C 地图 只是想知道STL图的实现 我读到它采用了二叉搜索树 STL中有哈希表的实现吗 STL映射到底是如何存储键值对的 典型的 STL 实现基于红黑树 C TR1 提供了 std tr1 unordered map 它使用
  • 如何在 JMeter 中进行 OAuth 2.0 身份验证?

    我正在尝试对一些需要身份验证的 API OAuth 2 0 进行功能测试 并在 JMeter 中进行模拟 我正在尝试验证 Azure 云的 OAuth 服务 有没有人能够成功创建 JMeter HTTP 请求来针对 OAuth 2 0 进行
  • 在文本选择上显示自定义菜单

    您好 我希望能够在用户选择一些与媒体提供的文本非常相似的文本时显示自定义菜单 或上下文菜单 如何实现这样的事情 我知道本机 jquery 上下文菜单插件 但我如何知道用户何时选择文本 浏览器的onselect似乎仅在输入元素上受支持 这是一
  • PHP 的合并函数?

    许多编程语言都有合并函数 返回第一个非 NULL 值 example 遗憾的是 2009 年 PHP 还没有做到这一点 在 PHP 本身获得合并函数之前 在 PHP 中实现一个合并函数的好方法是什么 php 5 3 中有一个新的运算符可以执
  • 如何在 cmd start 中使用引号?

    这是我想做的事 start wait c Program Files NetDrive2 nd2cmd exe c m t ftp blabla If I do start wait c Program Files NetDrive2 nd
  • 如何在 Anaconda Env 中启动 Visual Studio Code

    我在 Windows 10 PC 上的 Visual Studio Code 中运行 Python 程序时遇到问题 当我从终端启动 python 会话并说import cv2我没有收到任何错误 当我通过命令提示符并启动时VSCode从环境中
  • 为什么 UI 元素必须始终从 UI 线程创建/更新?

    为什么 UI 元素必须始终从 UI 线程创建 更新 在 几乎 所有编程语言中 UI 元素只能从 UI 线程安全地访问 修改 我知道这是一个标准的并发访问和同步问题 但真的有必要吗 这种行为是由编程语言还是操作系统强加的 有没有什么编程语言可
  • Django - 仅包含日期部分的分组

    MyModel objects filter created at gte 2011 03 09 created at lte 2011 03 11 values created at status annotate status coun
  • 作为 Cowboy 客户端,您如何使用 Gun?

    我跟着入门说明对于 Cowboy 我让 Cowboy 在端口 8080 上运行并侦听 然后我得到了Hello Erlang 当我进入时的回应http localhost 8080在我的浏览器中 现在 如何使用 Gun 连接到 Cowboy