Erlang模块gen_tcp翻译
概述
TCP/IP套接字接口
描述
gen_tcp模塊提供了使用TCP / IP協議與套接字進行通信的功能。
以下代碼片段提供了一個客戶端連接到端口5678的服務器的簡單示例,傳輸一個二進制文件并關閉連接:
client() ->
????SomeHostInNet = "localhost", % to make it runnable on one machine
????{ok, Sock} = gen_tcp:connect(SomeHostInNet, 5678, [binary, {packet, 0}]),
????ok = gen_tcp:send(Sock, "Some Data"),
ok = gen_tcp:close(Sock).
在另一端,服務器正在偵聽端口5678,接受連接并接收二進制文件:
server() ->
????{ok, LSock} = gen_tcp:listen(5678, [binary, {packet, 0},
????????????????????????????????????????{active, false}]),
????{ok, Sock} = gen_tcp:accept(LSock),
????{ok, Bin} = do_recv(Sock, []),
????ok = gen_tcp:close(Sock),
????Bin.
?
do_recv(Sock, Bs) ->
????case gen_tcp:recv(Sock, 0) of
????????{ok, B} ->
????????????do_recv(Sock, [Bs, B]);
????????{error, closed} ->
????????????{ok, list_to_binary(Bs)}
end.
有關更多示例,請參閱示例部分。
?
數據類型
option()?= {active, true | false | once}
?????????| {buffer, integer() >= 0}
?????????| {delay_send, boolean()}
?????????| {deliver, port | term}
?????????| {dontroute, boolean()}
?????????| {exit_on_close, boolean()}
?????????| {header, integer() >= 0}
?????????| {high_msgq_watermark, integer() >= 1}
?????????| {high_watermark, integer() >= 0}
?????????| {keepalive, boolean()}
?????????| {linger, {boolean(), integer() >= 0}}
?????????| {low_msgq_watermark, integer() >= 1}
?????????| {low_watermark, integer() >= 0}
?????????| {mode, list | binary}
?????????| list
?????????| binary
?????????| {nodelay, boolean()}
?????????| {packet,
????????????0 |
????????????1 |
????????????2 |
????????????4 |
????????????raw |
????????????sunrm |
????????????asn1 |
????????????cdr |
????????????fcgi |
????????????line |
????????????tpkt |
????????????http |
????????????httph |
????????????http_bin |
????????????httph_bin}
?????????| {packet_size, integer() >= 0}
?????????| {priority, integer() >= 0}
?????????| {raw,
????????????Protocol :: integer() >= 0,
????????????OptionNum :: integer() >= 0,
????????????ValueBin :: binary()}
?????????| {recbuf, integer() >= 0}
???| {reuseaddr, boolean()}
?????????| {send_timeout, integer() >= 0 | infinity}
?????????| {send_timeout_close, boolean()}
?????????| {sndbuf, integer() >= 0}
?????????| {tos, integer() >= 0}
?????????| {ipv6_v6only, boolean()}
option_name()?= active
??????????????| buffer
??????????????| delay_send
??????????????| deliver
??????????????| dontroute
??????????????| exit_on_close
??????????????| header
??????????????| high_msgq_watermark
??????????????| high_watermark
??????????????| keepalive
??????????????| linger
??????????????| low_msgq_watermark
??????????????| low_watermark
??????????????| mode
??????????????| nodelay
??????????????| packet
??????????????| packet_size
??????????????| priority
??????????????| {raw,
?????????????????Protocol :: integer() >= 0,
?????????????????OptionNum :: integer() >= 0,
?????????????????ValueSpec :: (ValueSize :: integer() >= 0)
????????????????????????????| (ValueBin :: binary())}
??????????????| recbuf
??????????????| reuseaddr
??????????????| send_timeout
??????????????| send_timeout_close
??????????????| sndbuf
??????????????| tos
??????????????| ipv6_v6only
connect_option()?= {ip,?inet:ip_address()}
?????????????????| {fd, Fd :: integer() >= 0}
?????????????????| {ifaddr,?inet:ip_address()}
?????????????????|?inet:address_family()
?????????????????| {port,?inet:port_number()}
?????????????????| {tcp_module, module()}
?????????????????|?option()
listen_option()?= {ip,?inet:ip_address()}
????????????????| {fd, Fd :: integer() >= 0}
????????????????| {ifaddr,?inet:ip_address()}
????????????????|?inet:address_family()
????????????????| {port,?inet:port_number()}
????????????????| {backlog, B :: integer() >= 0}
????????????????| {tcp_module, module()}
????????????????|?option()
socket()
由accept/ 1,2和connect/ 3,4返回。
?
導出
connect(Address, Port, Options) -> {ok, Socket} | {error, Reason}
connect(Address, Port, Options, Timeout) ->?{ok, Socket} | {error, Reason}
Types:
Address =?inet:ip_address()?|?inet:hostname()
Port =?inet:port_number()
Options = [connect_option()]
Timeout = timeout()
Socket =?socket()
Reason =?inet:posix()
連接到IP地址為Address的主機上的TCP端口Port上的服務器。 Address參數可以是主機名或IP地址。
{ip, ip_address()}
如果主機有多個網絡接口,則此選項指定要使用哪一個。
{ifaddr, ip_address()}
與{ip, ip_address()}相同。 如果主機有多個網絡接口,則此選項指定要使用哪一個。
{fd, integer() >= 0}
如果某個套接字在不使用gen_tcp的情況下以某種方式連接,請使用此選項為其傳遞文件描述符。
inet
設置IPv4的套接字。
inet6
設置IPv6的套接字。
{port, Port}
指定要使用的本地端口號。
{tcp_module, module()}
覆蓋使用哪個回調模塊。 默認為IPv4的inet_tcp和IPv6的inet6_tcp。
Opt
參見?inet:setopts/2.
可以使用send / 2將數據包發送到返回的套接字Socket。 從對等方發送的數據包將作為消息發送:
{tcp, Socket, Data}
如果套接字已關閉,則會傳遞以下消息:
{tcp_closed, Socket}
如果套接字上發生錯誤,則傳遞以下消息:
{tcp_error, Socket, Reason}
除非在套接字的選項列表中指定{active,false},在這種情況下,通過調用recv/?2來檢索數據包。
可選的Timeout參數指定以毫秒為單位的超時。 默認值是無窮大。
注意:
給予連接的選項的默認值可能受內核配置參數inet_default_connect_options的影響。 有關詳細信息,請參閱inet(3)。
?
listen(Port, Options) -> {ok, ListenSocket} | {error, Reason}
Types:
Port =?inet:port_number()
Options = [listen_option()]
ListenSocket =?socket()
Reason = system_limit |?inet:posix()
設置套接字以偵聽本地主機上的端口Port。
如果Port== 0,則底層操作系統會分配一個可用端口號,請使用inet:port/1來檢索它。
可用的選項是:
list
接收到的數據包作為列表提供。
binary
接收到的數據包以二進制形式提供。
{backlog, B}
B是>= 0的整數。backlog值默認為5。backlog值定義待處理連接隊列可能增長到的最大長度。
{ip, ip_address()}
如果主機有多個網絡接口,則此選項指定要監聽哪個接口。
{port, Port}
指定要使用的本地端口號。
{fd, Fd}
如果某個套接字在不使用gen_tcp的情況下以某種方式連接,請使用此選項為其傳遞文件描述符。
{ifaddr, ip_address()}
與{ip,ip_address()}相同。 如果主機有多個網絡接口,則此選項指定要使用哪一個。
inet
設置IPv4的套接字。
inet6
設置IPv6的套接字。
{tcp_module, module()}
覆蓋使用哪個回調模塊。 默認為IPv4的inet_tcp和IPv6的inet6_tcp。
Opt
參見?inet:setopts/2。
返回的套接字ListenSocket只能用于accept/1,2的調用。
注意:
監聽選項的默認值可能受內核配置參數inet_default_listen_options的影響。有關詳細信息,請參閱inet(3)。
?
accept(ListenSocket) -> {ok, Socket} | {error, Reason}
accept(ListenSocket, Timeout) -> {ok, Socket} | {error, Reason}
Types:
ListenSocket =?socket()
listen/2返回。
Timeout = timeout()
Socket =?socket()
Reason = closed | timeout | system_limit |?inet:posix()
在偵聽套接字上接受傳入的連接請求。套接字必須是從listen / 2返回的套接字。 超時以ms為單位指定超時值,默認為無窮大。
如果連接已建立,則返回{ok,Socket};如果ListenSocket已關閉,則返回{error,closed};如果在指定的時間內未建立連接,則返回{error,timeout};如果所有可用端口都處于連接狀態,則返回{error,system_limit} 。 如果出現其他問題,也可能返回一個POSIX錯誤值,請參閱inet(3)了解可能的錯誤值。
可以使用send/2將數據包發送到返回的套接字Socket。從對等方發送的數據包將作為消息發送:
{tcp, Socket, Data}
除非在偵聽套接字的選項列表中指定了{active,false},在這種情況下,通過調用recv/2來檢索數據包。
注意:
值得注意的是,接受調用不必從套接字所有者進程發出。 使用仿真器5.5.3及更高版本,可以從不同進程發出多個同時接受調用,這允許接收器進程池處理傳入連接。
?
send(Socket, Packet) -> ok | {error, Reason}
Types:
Socket =?socket()
Packet = iodata()
Reason = closed |?inet:posix()
在套接字上發送數據包。
發送調用沒有超時選項,如果需要超時,可以使用send_timeout套接字選項。請參閱示例部分。
?
recv(Socket, Length) -> {ok, Packet} | {error, Reason}
recv(Socket, Length, Timeout) -> {ok, Packet} | {error, Reason}
Types:
Socket =?socket()
Length = integer() >= 0
Timeout = timeout()
Packet = string() | binary() | HttpPacket
Reason = closed |?inet:posix()
HttpPacket = term()
請參閱erlang中的HttpPacket說明:decode_packet/3。.
該函數以被動模式從套接字接收數據包。關閉的套接字由返回值{error,closed}表示。
Length參數僅在套接字處于原始模式時才有意義,并且表示要讀取的字節數。 如果Length = 0,則返回所有可用的字節。 如果長度> 0,則返回確切的長度字節或錯誤; 當套接字從另一端關閉時可能丟棄少于Length數據的字節數據。
可選的Timeout參數指定以毫秒為單位的超時。默認值是無窮大。
?
controlling_process(Socket, Pid) -> ok | {error, Reason}
Types:
Socket =?socket()
Pid = pid()
Reason = closed | not_owner |?inet:posix()
為Socket分配一個新的控制進程Pid。 控制過程是從套接字接收消息的過程。 如果被當前控制進程以外的任何其他進程調用,則返回{error,not_owner}。
?
close(Socket) -> ok
Types:
Socket =?socket()
關閉TCP套接字。
?
shutdown(Socket, How) -> ok | {error, Reason}
Types:
Socket =?socket()
How = read | write | read_write
Reason =?inet:posix()
立即關閉一個或兩個方向的套接字。
How==write意味著關閉寫入套接字,從它讀取仍然是可能的。
為了能夠處理對端在寫入端執行關閉操作,{exit_on_close,false}選項很有用。
?
例子
以下示例通過將服務器實現為在單個偵聽套接字上進行接受的多個工作進程來說明{active,once}選項和多個接受的用法。 start/ 2函數使用工作進程的數量以及端口號監聽即將到來的連接。 如果LPort指定為0,則使用臨時端口號,為什么start函數返回分配的實際端口號:
start(Num,LPort) ->
????case gen_tcp:listen(LPort,[{active, false},{packet,2}]) of
????????{ok, ListenSock} ->
????????????start_servers(Num,ListenSock),
????????????{ok, Port} = inet:port(ListenSock),
????????????Port;
????????{error,Reason} ->
????????????{error,Reason}
????end.
?
start_servers(0,_) ->
????ok;
start_servers(Num,LS) ->
????spawn(?MODULE,server,[LS]),
????start_servers(Num-1,LS).
?
server(LS) ->
????case gen_tcp:accept(LS) of
????????{ok,S} ->
????????????loop(S),
????????????server(LS);
????????Other ->
????????????io:format("accept returned ~w - goodbye!~n",[Other]),
????????????ok
????end.
?
loop(S) ->
????inet:setopts(S,[{active,once}]),
????receive
????????{tcp,S,Data} ->
????????????Answer = process(Data), % Not implemented in this example
????????????gen_tcp:send(S,Answer),
????????????loop(S);
????????{tcp_closed,S} ->
????????????io:format("Socket ~w closed [~w]~n",[S,self()]),
????????????ok
end.
一個簡單的客戶端可能是這樣的:
client(PortNo,Message) ->
????{ok,Sock} = gen_tcp:connect("localhost",PortNo,[{active,false},{packet,2}]),
????gen_tcp:send(Sock,Message),
????A = gen_tcp:recv(Sock,0),
????gen_tcp:close(Sock),
? ? A.
發送調用不接受超時選項這一事實是因為發送超時是通過套接字選項send_timeout處理的。沒有接收器的發送操作的行為在很大程度上由底層TCP堆棧以及網絡基礎結構定義。 如果想編寫處理掛起的接收器的代碼,最終可能會導致發送者掛起發送調用,則可以編寫如下代碼。
? 考慮一個從客戶端進程接收數據的進程,該進程將被轉發到網絡上的服務器。該進程已通過TCP / IP連接到服務器,并且不會對其發送的每條消息進行確認,但必須依賴發送超時選項來檢測另一端是否無響應。連接時我們可以使用send_timeout選項:
?? ...
????{ok,Sock} = gen_tcp:connect(HostAddress, Port,[{active,false},{send_timeout, 5000},{packet,2}]),
loop(Sock), % See below
... ???
在處理請求的循環中,我們現在可以檢測發送超時:
loop(Sock) ->
????receive
????????{Client, send_data, Binary} ->
????????????case gen_tcp:send(Sock,[Binary]) of
????????????????{error, timeout} ->
????????????????????io:format("Send timeout, closing!~n",[]),
????????????????????handle_send_timeout(), % Not implemented here
????????????????????Client ! {self(),{error_sending, timeout}},
????????????????????%% Usually, it's a good idea to give up in case of a
????????????????????%% send timeout, as you never know how much actually
????????????????????%% reached the server, maybe only a packet header?!
????????????????????gen_tcp:close(Sock);
????????????????{error, OtherSendError} ->
????????????????????io:format("Some other error on socket (~p), closing",[OtherSendError]),
????????????????????Client ! {self(),{error_sending, OtherSendError}},
????????????????????gen_tcp:close(Sock);
????????????????ok ->
????????????????????Client ! {self(), data_sent},
????????????????????loop(Sock)
????????????end
end. ???
通常,只需檢測接收超時就足夠了,因為大多數協議都包含來自服務器的某種確認,但如果協議是嚴格意義上的一種方法,那么send_timeout選項就派上用場了!
轉載于:https://www.cnblogs.com/sunbin-hello/p/9238621.html
總結
以上是生活随笔為你收集整理的Erlang模块gen_tcp翻译的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么是同源策略及限制
- 下一篇: pixlabxi的指南