概述

  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翻译相关推荐

  1. Erlang模块erl翻译

    命令: erl 概述: Erlang模拟器 描述: erl程序启动一个Erlang运行时系统.准确的信息是依赖于系统的(举例,erl是否是脚本或程序,其它程序调用). 相反,windows用户可能想要 ...

  2. erlang nif中文翻译手册

    不错的翻译,记录下来,供以后翻阅,地址如下: http://dp0304.com/erlang/2012/09/20/erlang_nif_chinese

  3. python英译汉库模块_翻译|Python标准功能库1

    上班的时候偷懒,把Python帮助里的标准功能库1过了一遍,顺便翻译了一下,虽然我知道基本没有人看,但不是说21世纪编程能力是基本的生存力嘛. 通过阅读本文,你将了解Python的11个标准功能库1. ...

  4. [Erlang]port(gen_tcp)如何并行?

    R16B发布的时候,其中一个很大的亮点就是R16B port并行机制, 摘抄官方的release note如下: – Latency of signals sent from processes to ...

  5. 【原创】erlang 模块之 epmd

    2019独角兽企业重金招聘Python工程师标准>>> 什么是 epmd ? 在<Erlang/OTP 并发编程实战>中,对 epmd 有如下描述: epmd  代表 E ...

  6. elixir添加erlang模块

    elixir 添加依赖一般都是在hex仓库中 在mix.exs的deps函数中写入 defp deps do[{:my_dep, "~> 0.3.0"}]end#执行mix ...

  7. ITE EC(IT81202)--- PMC模块手册翻译

    PMC Power Management Channel 6.7.1概述 电源管理通道在ACPI规范中定义,用作主机处理器和嵌入式控制器之间的通信通道. 6.7.2功能 支持五个PM通道 支持通道1的 ...

  8. 【原创】erlang 模块之 application

    2019独角兽企业重金招聘Python工程师标准>>> kernel-2.15.2 中的内容 1 2 3 4 5 6 7 8 9 10 11 12 13 14 转载于:https:/ ...

  9. ITE EC(IT81202)--- SMFI模块手册翻译

    6.4 SMFI Shared Memory Flash Interface Bridge 6.4.1概述 Bridge提供主机访问共享内存.它还提供映射到主机域地址空间的EC代码地址空间,以及用于读 ...

最新文章

  1. 对比四种爬虫定位元素方法,你更爱哪个?
  2. 我是买家的前世今生,该到了say goodbye的时候了!
  3. Css实现checkbox及radio样式自定义
  4. Linux Java连接MySQL数据库
  5. v-for中为什么要有key属性
  6. lucene之创建索引代码
  7. SAP FSM 学习笔记(三) 在微信里发起SAP FSM客户预约
  8. 万用表怎么测量电池容量_家电常识丨万用表的测量应用学习
  9. scanf( )函数的返回值
  10. 基于IP子网将加域的电脑移动到不同的OU
  11. 深度linux 2014 体验机预览,[视频]深度Linux体验机计划
  12. Giter8 -- 把项目布局模板放到 GitHub 上
  13. mac头和ip头部详解
  14. loadrunner 11下载及破解
  15. 华为手机计算机怎么用根号,根号下怎么打_根号怎么打出来华为_根号怎么打出来手机-Guide信息网...
  16. 批量处理word文档向下箭头
  17. 最佳实战 | 如何使用腾讯云微搭从0到1开发企业门户应用
  18. 【檀越剑指大厂--mysql】mysql基础篇
  19. Lightswitch Desktopclinet 中如何调用WEB API
  20. 最小二乘法的曲线拟合方法在MATLAB中的实现

热门文章

  1. WinCE驱动编写小结
  2. 在线英汉词典 智能纠错的设计
  3. Tensorflow 读取XML文件内容并对图片等比例缩放
  4. HDOJ_2010_大二写_水仙花数
  5. Hadoop单机/伪分布式集群搭建(新手向)
  6. SAP不同的产品是如何支持用户创建自定义字段的
  7. iptables一次性封多个ip,使用ipset 工具
  8. 6.Mybatis中的动态Sql和Sql片段(Mybatis的一个核心)
  9. oc中代理的简单运用
  10. 到底什么是MiddleWare(中间件),请用plain English描述