2015-09-05 53 views
0

多线程的不工作后下面是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,并且不会将错误输出到命令行。

这里有什么可能出现的问题?提前致谢。

回答

3

这是由于竞争状态,其中前衍生进程可以回复插座被关闭。该handler/1函数调用request/1,而这也正是该spawn时发送的回复。一旦spawn开始新的进程调用reply/2,它立即返回,request/1然后返回到handler/1,而reply/2在新的进程中执行,并仍试图用插座,立即关闭套接字。

您可以从handler/1中删除​​的呼叫,因为reply/2函数在回复后调用它。

如果你想看到在二郎山一个小的HTTP服务器的一个例子,看到我simple web server

+0

谢谢,它的工作原理:] – Judking

+0

另一个问题弹出我的,你可以看看这个http://stackoverflow.com/questions/32416651/simulation-of-thread-pool-for-a-web-服务器实现逐二郎-犯规工作?多谢兄弟! – Judking