拿到了Programming Erlang的电子书,研究一下Potian先前跟俺说的“Socket Base Distribution”部分代码,结果发现chat_client.erl(对应书上的Chapter 11 IRC Lite),运行出错,提示
[quote]lib_chan_mm: protocol error:{login,"general","joe"}[/quote]
查看lib_chan_mm.erl,可见如下代码:
[code]loop1(Socket, Pid, Trace) ->
receive
{tcp, Socket, Bin} ->
Term = binary_to_term(Bin),
trace_it(Trace,{socketReceived, Term}),
Pid ! {chan, self(), Term},
loop1(Socket, Pid, Trace);
{tcp_closed, Socket} ->
trace_it(Trace, socketClosed),
Pid ! {chan_closed, self()};
{'EXIT', Pid, Why} ->
trace_it(Trace,{controllingProcessExit, Why}),
gen_tcp:close(Socket);
{setController, Pid1} ->
trace_it(Trace, {changedController, Pid}),
loop1(Socket, Pid1, Trace);
{trace, Trace1} ->
trace_it(Trace, {setTrace, Trace1}),
loop1(Socket, Pid, Trace1);
close ->
trace_it(Trace, closedByClient),
gen_tcp:close(Socket);
{send, Term} ->
trace_it(Trace, {sendingMessage, Term}),
gen_tcp:send(Socket, term_to_binary(Term)),
loop1(Socket, Pid, Trace);
UUg ->
io:format("lib_chan_mm: protocol error:~p~n",[UUg]),
loop1(Socket, Pid, Trace)
end.[/code]
可见此Middle Man进程接收到“{login,"general","joe"}”这样的原始数据了,估计是客户端代码直接发过去的,果然如此:
[code]MM ! {login, Group, Nick},
MM ! {relay, Nick, Str},[/code]
居然有这样的代码在客户端。修正bug很简单,在 lib_chan_mm.erl 有这个函数:
[code]send(Pid, Term) -> Pid ! {send, Term}.[/code]
替换一下,将
[code]MM ! {login, Group, Nick},[/code]
这类,换成
[code]lib_chan_mm:send(MM, {login, Group, Nick}),[/code]
客户端可以了,但接着发现,服务器端出问题了 :?
[quote]2> lib_chan_mm: protocol error:ack
2> lib_chan_mm: protocol error:{msg,"joe",<0.35.0>,"I'm starting the group"}[/quote]
检查chat_server.erl,最后将问题定位在chat_group.erl,修改
[code]C ! ack,
foreach(fun({Pid,_}) -> Pid ! {msg, Nick, C, Str} end, L),[/code]
为
[code]lib_chan_mm:send(C, ack),
foreach(fun({Pid,_}) -> lib_chan_mm:send(Pid, {msg, Nick, C, Str}) end, L),[/code]
再试,sigh,客户端又出问题
[code]2> chat_client login unexpected:{chan,
<0.40.0>,
{msg,
"joe",
<0.45.0>,
"I'm starting the group"}}[/code]
晕了,再次将
[code]{MM, ack} ->
{MM,{msg,From,Pid,Str}} ->[/code]
改为
[code]{chan, MM, ack} ->
{chan, MM,{msg,From,Pid,Str}} ->[/code]
重新编译和启动服务器和客户端,终于可以了 :lol:
[quote]3> chat_server:start().
lib_chan starting:"chat.conf"
ConfigData=[{port,2223},
{service,chat,
password,
"AsDT67aQ",
mfa,
mod_chat_controller,
start,
[]}]
true
4> mod_chat_controller off we go ...<0.45.0>
4> group controller received Msg={chan_closed,<0.45.0>}
4> server error should die with exit(normal) was:{mm_closed,<0.45.0>}
4> mod_chat_controller off we go ...<0.48.0>
4> group controller received Msg={chan,<0.48.0>,{relay,"joe"," haha"}}
4> group controller received Msg={chan,<0.48.0>,close}
4> mod_chat_controller off we go ...<0.51.0>
4> mod_chat_controller off we go ...<0.55.0>
4> mod_chat_controller off we go ...<0.53.0>
4> mod_chat_controller off we go ...<0.57.0>
4> group controller received Msg={chan,<0.51.0>,{relay,"joe"," welcome all"}}[/quote]
[quote]2> chat_client:test().
<0.39.0>
3> chat_client login unexpected:{'EXIT',<0.52.0>,connectorFinished}
3> chat_client login unexpected:{'EXIT',<0.48.0>,connectorFinished}
3> chat_client login unexpected:{'EXIT',<0.50.0>,connectorFinished}
3> chat_client login unexpected:{'EXIT',<0.46.0>,connectorFinished}[/quote]
在弹出的窗口里面自由聊天吧。至于为什么客户端会输出“chat_client login unexpected:{'EXIT',<0.46.0>,connectorFinished}”这样的信息,是因为try_to_connect函数里面,exit(connectorFinished)执行后会发送一个'EXIT'事件给client进程。
顺便附上修改过后的代码吧,等此书正式release了,估计代码也改过来了吧。
[quote]lib_chan_mm: protocol error:{login,"general","joe"}[/quote]
查看lib_chan_mm.erl,可见如下代码:
[code]loop1(Socket, Pid, Trace) ->
receive
{tcp, Socket, Bin} ->
Term = binary_to_term(Bin),
trace_it(Trace,{socketReceived, Term}),
Pid ! {chan, self(), Term},
loop1(Socket, Pid, Trace);
{tcp_closed, Socket} ->
trace_it(Trace, socketClosed),
Pid ! {chan_closed, self()};
{'EXIT', Pid, Why} ->
trace_it(Trace,{controllingProcessExit, Why}),
gen_tcp:close(Socket);
{setController, Pid1} ->
trace_it(Trace, {changedController, Pid}),
loop1(Socket, Pid1, Trace);
{trace, Trace1} ->
trace_it(Trace, {setTrace, Trace1}),
loop1(Socket, Pid, Trace1);
close ->
trace_it(Trace, closedByClient),
gen_tcp:close(Socket);
{send, Term} ->
trace_it(Trace, {sendingMessage, Term}),
gen_tcp:send(Socket, term_to_binary(Term)),
loop1(Socket, Pid, Trace);
UUg ->
io:format("lib_chan_mm: protocol error:~p~n",[UUg]),
loop1(Socket, Pid, Trace)
end.[/code]
可见此Middle Man进程接收到“{login,"general","joe"}”这样的原始数据了,估计是客户端代码直接发过去的,果然如此:
[code]MM ! {login, Group, Nick},
MM ! {relay, Nick, Str},[/code]
居然有这样的代码在客户端。修正bug很简单,在 lib_chan_mm.erl 有这个函数:
[code]send(Pid, Term) -> Pid ! {send, Term}.[/code]
替换一下,将
[code]MM ! {login, Group, Nick},[/code]
这类,换成
[code]lib_chan_mm:send(MM, {login, Group, Nick}),[/code]
客户端可以了,但接着发现,服务器端出问题了 :?
[quote]2> lib_chan_mm: protocol error:ack
2> lib_chan_mm: protocol error:{msg,"joe",<0.35.0>,"I'm starting the group"}[/quote]
检查chat_server.erl,最后将问题定位在chat_group.erl,修改
[code]C ! ack,
foreach(fun({Pid,_}) -> Pid ! {msg, Nick, C, Str} end, L),[/code]
为
[code]lib_chan_mm:send(C, ack),
foreach(fun({Pid,_}) -> lib_chan_mm:send(Pid, {msg, Nick, C, Str}) end, L),[/code]
再试,sigh,客户端又出问题
[code]2> chat_client login unexpected:{chan,
<0.40.0>,
{msg,
"joe",
<0.45.0>,
"I'm starting the group"}}[/code]
晕了,再次将
[code]{MM, ack} ->
{MM,{msg,From,Pid,Str}} ->[/code]
改为
[code]{chan, MM, ack} ->
{chan, MM,{msg,From,Pid,Str}} ->[/code]
重新编译和启动服务器和客户端,终于可以了 :lol:
[quote]3> chat_server:start().
lib_chan starting:"chat.conf"
ConfigData=[{port,2223},
{service,chat,
password,
"AsDT67aQ",
mfa,
mod_chat_controller,
start,
[]}]
true
4> mod_chat_controller off we go ...<0.45.0>
4> group controller received Msg={chan_closed,<0.45.0>}
4> server error should die with exit(normal) was:{mm_closed,<0.45.0>}
4> mod_chat_controller off we go ...<0.48.0>
4> group controller received Msg={chan,<0.48.0>,{relay,"joe"," haha"}}
4> group controller received Msg={chan,<0.48.0>,close}
4> mod_chat_controller off we go ...<0.51.0>
4> mod_chat_controller off we go ...<0.55.0>
4> mod_chat_controller off we go ...<0.53.0>
4> mod_chat_controller off we go ...<0.57.0>
4> group controller received Msg={chan,<0.51.0>,{relay,"joe"," welcome all"}}[/quote]
[quote]2> chat_client:test().
<0.39.0>
3> chat_client login unexpected:{'EXIT',<0.52.0>,connectorFinished}
3> chat_client login unexpected:{'EXIT',<0.48.0>,connectorFinished}
3> chat_client login unexpected:{'EXIT',<0.50.0>,connectorFinished}
3> chat_client login unexpected:{'EXIT',<0.46.0>,connectorFinished}[/quote]
在弹出的窗口里面自由聊天吧。至于为什么客户端会输出“chat_client login unexpected:{'EXIT',<0.46.0>,connectorFinished}”这样的信息,是因为try_to_connect函数里面,exit(connectorFinished)执行后会发送一个'EXIT'事件给client进程。
顺便附上修改过后的代码吧,等此书正式release了,估计代码也改过来了吧。