小超同學遇到一個問題:gen_tcp:send方法報錯, Bad value on output port 'tcp_inet';按照字面意思是發往port的數據值是bad value;
打開erl5.9\lib\kernel-2.15\src\gen_tcp.erl看一下gen_tcp的源碼:
%% %% Send %% -spec send(Socket, Packet) -> ok | {error, Reason} when Socket :: socket(), Packet :: iodata(), %%% <- 注意這里 Reason :: inet:posix(). send(S, Packet) when is_port(S) -> case inet_db:lookup_socket(S) of {ok, Mod} -> Mod:send(S, Packet); Error -> Error end.
從函數接口說明可以看出數據要求是iodata,估計出現'bad value'很有可能數據不是iodata,做個實驗看看:
Eshell V5.9 (abort with ^G) 1> {ok,S0}=gen_tcp:listen(5678,[]). {ok,#Port<0.506>} 2> {ok,S1}=gen_tcp:connect("localhost",5678,[]). {ok,#Port<0.517>} 3> {ok,S2}=gen_tcp:accept(S0). {ok,#Port<0.518>} 4> gen_tcp:send(S1,"message text\0"). ok 5> gen_tcp:send(S1,["message text",0]). ok 6> gen_tcp:send(S1,["message text我們",0]). ok 7> flush(). Shell got {tcp,#Port<0.518>,[109,101,115,115,97,103,101,32,116,101,120,116,0]} Shell got {tcp,#Port<0.518>,[109,101,115,115,97,103,101,32,116,101,120,116,0]} Shell got {tcp,#Port<0.518>, [109,101,115,115,97,103,101,32,116,101,120,116,206,210,195,199, 0]} ok 8> gen_tcp:send(S1,["message text我們",msg,0]). {error,einval} =ERROR REPORT==== 23-Aug-2012::11:37:23 === Bad value on output port 'tcp_inet' 9> gen_tcp:send(S1,["message text我們",0]). ok 10> gen_tcp:send(S1,["message text我們",12,0]). ok 11> gen_tcp:send(S1,["message text我們",1222,0]). {error,einval} =ERROR REPORT==== 23-Aug-2012::11:57:24 === Bad value on output port 'tcp_inet' 12>
重現了小超遇到的問題,,只要發送的數據不是iodata就會報Bad value on output port 'tcp_inet'的錯誤,根據這個線索,小超同學跟了一下果然由於協議層代碼問題導致發送的數據是error_protocol這樣一個原子.
關於iodata和iolist這個我之前整理過一篇文章[鏈接],這里只把iodata的定義再貼一遍:
iodata() = iolist() | binary()
iolist() maybe_improper_list(char() | binary() | iolist(), binary() | [])
maybe_improper_list() maybe_improper_list(any(), any())
byte() 0..255
char() 0..16#10ffffmaybe_improper_list(T) maybe_improper_list(T, any())
或者:IoData = unicode:chardata()
chardata() = charlist() | unicode_binary()
charlist() = [unicode_char() | unicode_binary() | charlist()]
unicode_binary() = binary()A binary() with characters encoded in the UTF-8 coding standard.
下面資料遇到的情況是同樣的原因:
[1] http://www.trapexit.org/forum/viewtopic.php?p=39602&sid=ba065c1a5b0c789b4383501784d416ec
[2] http://erlang.org/pipermail/erlang-questions/2009-September/046396.html
小圖一張