在 Erlang 中切换到多线程后,一个简单的 Web 服务器无法工作
A simple web-server is not working after switching to multithread in Erlang
这是 rudy.erl 的代码:
-module(rudy).
-export([init/1,handler/1,request/1,reply/2, start/1, stop/0]).
start(Port) ->
register(rudy, spawn(fun() ->
init(Port) end)).
stop() ->
exit(whereis(rudy), "time to die").
init(Port) ->
Opt = [list, {active, false}, {reuseaddr, true}],
case gen_tcp:listen(Port, Opt) of % opens a listening socket
{ok, Listen} ->
handler(Listen),
gen_tcp:close(Listen), % close the socket
ok;
{error, _Error} -> error
end.
handler(Listen) ->
case gen_tcp:accept(Listen) of % listen to the socket
{ok, Client} ->
request(Client),
gen_tcp:close(Client),
handler(Listen);
{error, _Error} -> error
end.
request(Client) ->
Recv = gen_tcp:recv(Client, 0),
case Recv of
{ok, Str} ->
Request = http:parse_request(Str),
%% spawn(rudy, reply, [Client, Request]);
reply(Client, Request);
{error, Error} ->
io:format("rudy: error: ~w~n", [Error])
end.
reply(Client, {{get, URI, _}, _, _}) ->
timer:sleep(40),
Response = http:ok(URI),
gen_tcp:send(Client, Response),
gen_tcp:close(Client).
如果我执行rudy:start(8027)
,它会通过访问http://localhost:8027/正常工作,但是如果我将reply(Client, Request);
转换为spawn(rudy, reply, [Client, Request]);
],无法访问前面的 URL,并且没有错误输出到命令行。
这里可能有什么问题?提前致谢。
这是由于竞争条件导致的,即套接字在生成的进程可以回复之前关闭。 handler/1
函数调用 request/1
,这就是 spawn
发生以发送回复的地方。一旦 spawn
启动新进程调用 reply/2
,它会立即 returns 然后 request/1
然后 returns 到 handler/1
,它会立即关闭套接字,同时reply/2
正在新进程中执行并仍在尝试使用套接字。
您可以删除 handler/1
中的 gen_tcp:close/1
调用,因为 reply/2
函数会在回复后调用它。
如果您想查看 Erlang 中的小型 HTTP 服务器示例,请参阅我的 simple web server。
这是 rudy.erl 的代码:
-module(rudy).
-export([init/1,handler/1,request/1,reply/2, start/1, stop/0]).
start(Port) ->
register(rudy, spawn(fun() ->
init(Port) end)).
stop() ->
exit(whereis(rudy), "time to die").
init(Port) ->
Opt = [list, {active, false}, {reuseaddr, true}],
case gen_tcp:listen(Port, Opt) of % opens a listening socket
{ok, Listen} ->
handler(Listen),
gen_tcp:close(Listen), % close the socket
ok;
{error, _Error} -> error
end.
handler(Listen) ->
case gen_tcp:accept(Listen) of % listen to the socket
{ok, Client} ->
request(Client),
gen_tcp:close(Client),
handler(Listen);
{error, _Error} -> error
end.
request(Client) ->
Recv = gen_tcp:recv(Client, 0),
case Recv of
{ok, Str} ->
Request = http:parse_request(Str),
%% spawn(rudy, reply, [Client, Request]);
reply(Client, Request);
{error, Error} ->
io:format("rudy: error: ~w~n", [Error])
end.
reply(Client, {{get, URI, _}, _, _}) ->
timer:sleep(40),
Response = http:ok(URI),
gen_tcp:send(Client, Response),
gen_tcp:close(Client).
如果我执行rudy:start(8027)
,它会通过访问http://localhost:8027/正常工作,但是如果我将reply(Client, Request);
转换为spawn(rudy, reply, [Client, Request]);
],无法访问前面的 URL,并且没有错误输出到命令行。
这里可能有什么问题?提前致谢。
这是由于竞争条件导致的,即套接字在生成的进程可以回复之前关闭。 handler/1
函数调用 request/1
,这就是 spawn
发生以发送回复的地方。一旦 spawn
启动新进程调用 reply/2
,它会立即 returns 然后 request/1
然后 returns 到 handler/1
,它会立即关闭套接字,同时reply/2
正在新进程中执行并仍在尝试使用套接字。
您可以删除 handler/1
中的 gen_tcp:close/1
调用,因为 reply/2
函数会在回复后调用它。
如果您想查看 Erlang 中的小型 HTTP 服务器示例,请参阅我的 simple web server。