当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


erlang setopts(Socket, Options)用法及代码示例


setopts(Socket, Options) -> ok | {error, posix()}
类型:
Socket = socket()
Options = [socket_setopt()]

为套接字设置一个或多个选项。

可以使用以下选项:


{active, true | false | once | N}

如果值为 true (默认值),则从套接字接收到的所有内容都会作为消息发送到接收进程。

如果值为false(被动模式),进程必须通过调用显式接收传入数据gen_tcp:recv/2,3,gen_udp:recv/2,3, 或者recv(Socket)(取决于插座的类型)。

如果值为 once ( {active, once} ),则来自套接字的一条数据消息将发送到进程。要再接收一条消息,必须使用选项 {active, once} 再次调用 setopts/2

如果该值为 -32768 到 32767(含)范围内的整数 N,则该值将添加到套接字发送到控制进程的数据消息的计数中。套接字的默认消息计数是 0 。如果指定负值,并且其大小等于或大于套接字的当前消息计数,则套接字的消息计数将设置为 0 。一旦套接字的消息计数达到 0 ,无论是因为将收到的数据消息发送到进程还是通过显式设置,都会通过一条特定于套接字类型的特殊消息通知进程,套接字已进入被动模式。一旦套接字进入被动模式,要接收更多消息,必须再次调用 setopts/2 将套接字设置回主动模式。

使用 {active, once}{active, N} 时,套接字在收到数据时会自动更改行为。与 connection-oriented 套接字(即 gen_tcp )结合使用时,这可能会造成混淆,因为具有 {active, false} 行为的套接字报告的关闭方式与具有 {active, true} 行为的套接字不同。为了简化编程,对等方关闭的套接字(在 {active, false} 模式下检测到此情况)在设置为 {active, once}{active, true}{active, N} 模式时仍会生成消息 {tcp_closed,Socket}。因此,可以安全地假设当套接字在 {active, true}{active, false} 模式之间来回更改时,最终会出现消息 {tcp_closed,Socket} ,可能随后是套接字端口终止(取决于选项 exit_on_close )。然而,当检测到对等关闭时,这完全取决于底层 TCP/IP 堆栈和协议。

请注意,{active, true} 模式不提供流量控制;快速的发送者可以很容易地让接收者溢出传入的消息。 {active, N} 模式也是如此,但消息计数大于零。

仅当您的高级协议提供自己的流量控制(例如,确认收到的消息)或交换的数据量较小时,才使用主动模式。 {active, false} 模式、使用 {active, once} 模式或 {active, N} 模式以及适合应用程序的 N 值提供流量控制。另一方的发送速度不能快于接收方的读取速度。


{broadcast, Boolean} (UDP sockets)

启用/禁用发送广播的权限。


{buffer, Size}

驱动程序使用的user-level缓冲区的大小。不要与选项混淆sndbufrecbuf,对应于内核套接字缓冲区。对于 TCP,建议val(buffer) >= val(recbuf)以避免由于不必要的复制而出现性能问题。对于 UDP,同样的建议适用,但最大值不应大于网络路径的 MTU。val(buffer)时自动设置为上述最大值recbuf已设置。然而,由于尺寸设置为recbuf通常会变得更大,鼓励您使用getopts/2分析您的操作系统的行为。

请注意,这也是可以从单个 recv 调用接收的最大数据量。如果您使用的 MTU 高于正常值,请考虑将缓冲区设置得更高。


{delay_send, Boolean}

通常,当 Erlang 进程发送到套接字时,驱动程序会尝试立即发送数据。如果失败,驱动程序将使用任何可用的方法将要发送的消息排队,只要操作系统表示它可以处理它。设置 {delay_send, true} 使所有消息排队。发送到网络的消息会更大但更少。该选项影响发送请求与 Erlang 进程的调度,而不是更改套接字的任何实际属性。该选项是特定于实现的。默认为 false


{deliver, port | term}

{active, true} 时,数据以 port : {S, {data, [H1,..Hsz | Data]}}term : {tcp, S, [H1..Hsz | Data]} 的形式传递。


{dontroute, Boolean}

启用/禁用传出消息的路由旁路。


{exit_on_close, Boolean}

默认情况下,此选项设置为true

将其设置为的唯一原因false是如果您想在检测到关闭后继续向套接字发送数据,例如,如果对等方使用gen_tcp:shutdown/2关闭写入端。


{exclusiveaddruse, Boolean}

在 Windows 上启用/禁用独占地址/端口使用。也就是说,通过启用此选项,您可以防止其他套接字绑定到同一地址/端口。默认情况下此选项被禁用。也就是说,其他套接字可以通过设置使用相同的地址/端口{reuseaddr, true}结合{reuseport, true}除非{exclusiveaddruse, true}已设置为Socket。在非 Windows 系统上,此选项将被默默忽略。


{header, Size}

仅当创建套接字时指定了选项 binary 时,此选项才有意义。如果指定了选项 header,则从套接字接收的前 Size 数据字节是列表的元素,其余数据是指定为同一列表尾部的二进制数据。例如,如果 Size == 2 ,则收到的数据与 [Byte1,Byte2|Binary] 匹配。


{high_msgq_watermark, Size}

当消息队列上的数据量达到此限制时,套接字消息队列将设置为繁忙状态。请注意,此限制仅涉及尚未到达 ERTS 内部套接字实现的数据。默认为 8 kB。

如果套接字消息队列繁忙或套接字本身繁忙,则向套接字发送数据的发送者将被挂起。

有关详细信息,请参阅选项 low_msgq_watermarkhigh_watermarklow_watermark

请注意,分发套接字禁用high_msgq_watermarklow_msgq_watermark。相反,使用分配缓冲区繁忙限制,这是一个类似的特征。


{high_watermark, Size} (TCP/IP sockets)

当 ERTS 套接字实现内部排队的数据量达到此限制时,套接字将设置为繁忙状态。默认为 8 kB。

如果套接字消息队列繁忙或套接字本身繁忙,则向套接字发送数据的发送者将被挂起。

有关详细信息,请参阅选项 low_watermarkhigh_msgq_watermarklow_msqg_watermark


{ipv6_v6only, Boolean}

限制套接字仅使用 IPv6,禁止任何 IPv4 连接。这仅适用于 IPv6 套接字(选项 inet6 )。

在大多数平台上,必须先在套接字上设置此选项,然后才能将其关联到地址。因此,只有在创建套接字时指定它才合理,而在调用函数时不使用它(setopts/2)包含此说明。

将此选项设置为 true 的套接字的行为是唯一可移植的。 FreeBSD 不推荐 IPv6 刚出现时对所有流量使用 IPv6 的最初想法(您可以使用 {ipv6_v6only,false} 覆盖推荐的系统默认值),OpenBSD(支持的 GENERIC 内核)禁止,并且在 Windows 上不可能(它具有独立的 IPv4 和 IPv6 协议栈)。大多数 Linux 发行版仍然具有系统默认值 false 。操作系统之间将 IPv6 与 IPv4 流量分开的政策转变已经演变,因为事实证明正确且安全地实现双栈是困难且复杂的。

在某些平台上,此选项唯一允许的值为 true ,例如 OpenBSD 和 Windows。在这种情况下,在创建套接字时尝试将此选项设置为 false 会失败。

在不存在此选项的平台上设置此选项将被忽略。获取此选项getopts/2无返回值,即返回的列表不包含{ipv6_v6only,_}元组。在 Windows 上,该选项不存在,但它被模拟为具有值的只读选项true.

因此,在创建套接字时将此选项设置为 true 永远不会失败,除非在您已将内核自定义为仅允许 false 的平台上,这在例如 OpenBSD 上是可行的(但很尴尬)。

如果您使用读回选项值getopts/2并且没有得到任何值,则该选项在主机操作系统中不存在。 IPv6 和 IPv4 套接字在同一端口上侦听的行为以及 IPv6 套接字获取 IPv4 流量的行为将不再可预测。


{keepalive, Boolean}(TCP/IP sockets)

当没有交换其他数据时,启用/禁用已连接套接字上的定期传输。如果另一端没有响应,则认为连接已断开,并向控制进程发送错误消息。默认为 false


{linger, {true|false, Seconds}}

确定 time-out(以秒为单位),用于刷新 close/1 套接字调用中未发送的数据。

第一个组件是是否启用了 linger,第二个组件是刷新 time-out,以秒为单位。有3种选择:


{false, _}

close/1 或 shutdown/2 立即返回,不等待数据刷新,关闭在后台发生。


{true, 0}

关闭时中止连接。丢弃发送缓冲区中仍保留的任何数据并将 RST 发送到对等方。

这避免了 TCP 的 TIME_WAIT 状态,但留下了创建此连接的另一个 "incarnation" 的可能性。


{true, Time} when Time > 0

close/1 或 shutdown/2 不会返回,直到套接字的所有排队消息均已成功发送或达到延迟超时 (Time)。


{low_msgq_watermark, Size}

如果套接字消息队列处于繁忙状态,则当消息队列中排队的数据量低于此限制时,套接字消息队列将设置为不繁忙状态。请注意,此限制仅涉及尚未到达 ERTS 内部套接字实现的数据。默认为 4 kB。

当套接字消息队列和套接字不忙时,由于消息队列繁忙或套接字繁忙而挂起的发送方将恢复。

有关详细信息,请参阅选项 high_msgq_watermarkhigh_watermarklow_watermark

请注意,分发套接字禁用high_msgq_watermarklow_msgq_watermark。相反,他们使用分配缓冲区繁忙限制,这是一个类似的特征。


{low_watermark, Size} (TCP/IP sockets)

如果套接字处于繁忙状态,则当 ERTS 套接字实现内部排队的数据量低于此限制时,套接字将设置为不繁忙状态。默认为 4 kB。

因消息队列繁忙或套接字繁忙而挂起的发送方会在套接字消息队列和套接字不繁忙时恢复。

有关详细信息,请参阅选项 high_watermarkhigh_msgq_watermarklow_msgq_watermark


{mode, Mode :: binary | list}

收到的 Packet 按照 Mode 的定义进行传递。


{netns, Namespace :: file:filename_all()}

设置套接字的网络命名空间。范围Namespace是定义命名空间的文件名,例如,"/var/run/netns/example",通常由命令创建ip netns add example。该选项必须在创建套接字的函数调用中使用,即connect(Address, Port, Opts),gen_tcp:listen/2,open(Port)或者open(), 并且getifaddrs/1.

此选项使用 Linux 特定的系统调用 setns() ,例如在 Linux 内核 3.0 或更高版本中,因此仅在为此类操作系统编译运行时系统时才存在。

虚拟机还需要提升权限,或者以超级用户身份运行,或者(对于 Linux)根据 setns(2) 的文档具有 CAP_SYS_ADMIN 函数。然而,在测试过程中,CAP_SYS_PTRACECAP_DAC_READ_SEARCH 也被证明是必要的。

例子:

setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp

请注意,包含虚拟机可执行文件(示例中的 beam.smp)的文件系统必须是本地的、不带标志 nosetuid 挂载的、支持扩展属性,并且内核必须支持文件函数。所有这些至少在 Ubuntu 12.04 LTS 上都可以开箱即用,只是 SCTP 套接字似乎不支持网络命名空间。

Namespace是一个文件名,按照模块中的讨论进行编码和解码文件,但以下情况除外:

  • 仿真器标志 +fnu 被忽略。

  • getopts/2如果无法解码存储的文件名,此选项将返回文件名的二进制文件。仅当您使用无法使用模拟器的文件名编码进行解码的二进制文件设置该选项时,才会发生这种情况:file:native_name_encoding/0.


{bind_to_device, Ifname :: binary()}

将套接字绑定到特定的网络接口。该选项必须在创建套接字的函数调用中使用,即connect(Address, Port, Opts),gen_tcp:listen/2,open(Port), 或者open().

不像getifaddrs/0, Ifname 被编码为二进制。在极少数情况下,系统在网络设备名称中使用非 7-bit-ASCII 字符,对此参数进行编码时必须特别小心。

此选项使用 Linux 特定的套接字选项 SO_BINDTODEVICE ,例如在 Linux 内核 2.0.30 或更高版本中,因此仅在为此类操作系统编译运行时系统时才存在。

在 Linux 3.8 之前,可以设置此套接字选项,但无法使用getopts/2。从Linux 3.8开始,它是可读的。

虚拟机还需要提升的权限,或者以超级用户身份运行,或者(对于 Linux)具有 CAP_NET_RAW 函数。

此选项的主要用例是将套接字绑定到Linux VRF 实例.


list

收到的 Packet 以列表形式传送。


binary

收到的 Packet 以二进制形式交付。


{nodelay, Boolean}(TCP/IP sockets)

如果Boolean == true,则为套接字打开选项TCP_NODELAY,这意味着也会立即发送少量数据。

domain = local 不支持此选项,但如果是inet_backend =/= socket,此错误将被忽略。


{nopush, Boolean}(TCP/IP sockets)

这在 BSD 上转换为 TCP_NOPUSH,在 Linux 上转换为 TCP_CORK

如果 Boolean == true ,则为套接字打开相应的选项,这意味着会累积少量数据,直到完整的 MSS-worth 数据可用或关闭此选项。

请注意,虽然 TCP_NOPUSH 套接字选项在 OSX 上可用,但其语义非常不同(例如,取消设置它不会导致立即发送累积数据)。因此,nopush 选项在 OSX 上被有意忽略。


{packet, PacketType}(TCP/IP sockets)

定义用于套接字的数据包类型。可能的值:


raw | 0

没有进行任何包装。


1 | 2 | 4

数据包包含一个标头,指定数据包中的字节数,后跟该字节数。标头长度可以是 1、2 或 4 个字节,并包含一个采用大端字节顺序的无符号整数。每个发送操作都会生成标头,并且标头会在每次接收操作时被剥离。

4 字节标头限制为 2Gb。


asn1 | cdr | sunrm | fcgi | tpkt | line

这些数据包类型仅对接收有影响。发送数据包时,应用程序有责任提供正确的标头。然而,在接收时,对于收到的每个完整数据包,都会向控制进程发送一条消息,并且类似地,每次调用 gen_tcp:recv/2,3 都会返回一个完整的数据包。标头没有被剥离。

报文类型的含义如下:

  • asn1 - ASN.1 BER
  • sunrm - Sun 的 RPC 编码
  • cdr - CORBA (GIOP 1.1)
  • fcgi - 快速 CGI
  • tpkt - TPKT 格式 [RFC1006]
  • line - 行模式,数据包是带有换行符的line-terminated,长于接收缓冲区的行将被截断

http | http_bin

超文本传输协议。返回的数据包格式如下HttpPacket说明于decode_packet(Type, Bin, Options)在 ERTS 中。被动模式下的套接字返回{ok, HttpPacket}gen_tcp:recv当活动套接字发送消息时,例如{http, Socket, HttpPacket}.


httph | httph_bin

通常不需要这两种类型,因为在读取第一行后,套接字会在内部自动从http /http_bin 切换到httph /httph_bin。但是,在某些情况下它们可能很有用,例如从分块编码中解析预告片。


{packet_size, Integer}(TCP/IP sockets)

设置数据包正文允许的最大长度。如果报文头指示报文的长度大于允许的最大长度,则认为该报文无效。如果数据包标头对于套接字接收缓冲区来说太大,也会发生同样的情况。

对于 line-oriented 协议( linehttp* ),选项 packet_size 还保证接受指定长度的行,并且不会因为内部缓冲区限制而被视为无效。


{line_delimiter, Char}(TCP/IP sockets)

设置 line-oriented 协议 ( line ) 的行定界字符。默认为 $\n


{raw, Protocol, OptionNum, ValueBin}

见下文。


{read_packets, Integer}(UDP sockets)

设置数据可用时无需套接字干预即可读取的 UDP 数据包的最大数量。当这么多数据包已被读取并传递到目标进程时,在新的可用数据通知到达之前不会读取新数据包。默认为 5 。如果此参数设置得太高,系统可能会因 UDP 数据包泛洪而变得无响应。


{recbuf, Size}

用于套接字的接收缓冲区的最小大小。鼓励您使用getopts/2检索操作系统设置的大小。


{recvtclass, Boolean}

如果设置为 true,则会激活在为套接字实现协议 IPPROTO_IPV6 选项 IPV6_RECVTCLASSIPV6_2292RECVTCLASS 的平台上返回接收到的 TCLASS 值。无论平台返回 IPV6_TCLASS 还是 IPV6_RECVTCLASS CMSG 值,该值都会作为 {tclass,TCLASS} 元组返回。

对于面向数据包的套接字,支持接收带有有效负载数据的辅助数据(gen_udpgen_sctp), 这TCLASS值在包含在一个扩展返回元组中返回辅助数据列表。对于面向流的套接字(gen_tcp)获得的唯一方法TCLASS值是平台是否支持 pktoptions 选项。


{recvtos, Boolean}

如果设置为 true,则会激活在为套接字实现协议 IPPROTO_IP 选项 IP_RECVTOS 的平台上返回接收到的 TOS 值。无论平台返回 IP_TOS 还是 IP_RECVTOS CMSG 值,该值都会以 {tos,TOS} 元组形式返回。

对于面向数据包的套接字,支持接收带有有效负载数据的辅助数据(gen_udpgen_sctp), 这TOS值在包含在一个扩展返回元组中返回辅助数据列表。对于面向流的套接字(gen_tcp)获得的唯一方法TOS值是平台是否支持 pktoptions 选项。


{recvttl, Boolean}

如果设置为 true,则会激活在为套接字实现协议 IPPROTO_IP 选项 IP_RECVTTL 的平台上返回接收到的 TTL 值。无论平台返回 IP_TTL 还是 IP_RECVTTL CMSG 值,该值都会以 {ttl,TTL} 元组形式返回。

对于面向数据包的套接字,支持接收带有有效负载数据的辅助数据(gen_udpgen_sctp), 这TTL值在包含在一个扩展返回元组中返回辅助数据列表。对于面向流的套接字(gen_tcp)获得的唯一方法TTL值是平台是否支持 pktoptions 选项。


{reuseaddr, Boolean}

允许或禁止重复使用本地地址。默认情况下,不允许重复使用。

注意

在窗户上{reuseaddr, true}不会有任何影响,除非也{reuseport, true}已设置。如果两者都设置了,则SO_REUSEADDRWindows 套接字选项将被启用。这自从设定SO_REUSEADDR在 Windows 上或多或少与设置两者具有相同的行为SO_REUSEADDRSO_REUSEPORT在 BSD 上。此行为是从 OTP 26.0 开始引入的。

改变

以前在 Windows 上的行为:

  • 在 OTP 25.0 之前,{reuseaddr, true} 选项被默默忽略。
  • 在 OTP 25.0 和 OTP 25.2 的前身之间,如果设置了 {reuseaddr, true},则设置了底层 SO_REUSEADDR 套接字选项。
  • 在 OTP 25.2 和 OTP 26.0 的前身之间,如果设置了 {reuseaddr, true},则仅在 UDP 套接字上设置底层 SO_REUSEADDR 套接字选项,并在其他套接字上默默忽略。

另请参阅exclusiveaddruse选项。


{reuseport, Boolean}

允许或禁止重复使用本地端口可以不可以根据底层操作系统进行负载平衡。默认情况下,不允许重复使用。也可以看看reuseport_lb.

注意

在窗户上{reuseport, true}不会有任何影响,除非也{reuseaddr, true}已设置。如果两者都设置了,则SO_REUSEADDRWindows 套接字选项将被启用。这自从设定SO_REUSEADDR在 Windows 上或多或少与设置两者具有相同的行为SO_REUSEADDRSO_REUSEPORT在 BSD 上。这reuseport从 OTP 26.0 开始引入该选项。

另请参阅exclusiveaddruse选项。

注意

reuseport 可以不可以与标的期权相同reuseport_lb取决于底层操作系统。例如,它们在 Linux 上。当它们是相同的基础选项时,对两者进行操作可能会导致它们以令人惊讶的方式相互作用。例如,通过启用reuseport然后禁用reuseport_lb两者最终都会被禁用。


{reuseport_lb, Boolean}

允许或禁止重复使用本地端口负载均衡。默认情况下,不允许重复使用。也可以看看reuseport.

注意

reuseport_lb 可以不可以与标的期权相同reuseport取决于底层操作系统。例如,它们在 Linux 上。当它们是相同的基础选项时,对两者进行操作可能会导致它们以令人惊讶的方式相互作用。例如,通过启用reuseport_lb然后禁用reuseport两者最终都会被禁用。


{send_timeout, Integer}

仅允许用于connection-oriented 套接字。

指定等待底层 TCP 堆栈接受发送操作的最长时间。当超出限制时,发送操作返回{error,timeout}。发送的数据包有多少是未知的;因此,只要发生time-out,套接字就会被关闭(参见下面的send_timeout_close)。默认为 infinity


{send_timeout_close, Boolean}

仅允许用于connection-oriented 套接字。

send_timeout 一起使用,指定当发送操作返回 {error,timeout} 时是否自动关闭套接字。推荐设置为 true ,它会自动关闭套接字。由于向后兼容性,默认为false


{show_econnreset, Boolean} (TCP/IP sockets)

当该选项设置为false默认情况下,从 TCP 对等方收到的 RST 被视为正常关闭(就像发送了 FIN)。调用者gen_tcp:recv/2得到{error, closed}。在主动模式下,控制进程接收{tcp_closed, Socket}消息,表明对端已关闭连接。

将此选项设置为true允许您区分正常关闭的连接和 TCP 对等方(有意或无意)中止的连接。调用gen_tcp:recv/2返回{error, econnreset}。在主动模式下,控制进程接收{tcp_error, Socket, econnreset}在平常之前发消息{tcp_closed, Socket},与任何其他套接字错误的情况一样。调用gen_tcp:send/2也返回{error, econnreset}当检测到 TCP 对等方已发送 RST 时。

从返回的已连接套接字accept(ListenSocket)继承了show_econnreset从监听套接字设置。


{sndbuf, Size}

用于套接字的发送缓冲区的最小大小。鼓励您使用getopts/2,检索操作系统设置的大小。


{priority, Integer}

在实现此函数的平台上设置 SO_PRIORITY 套接字级别选项。不同系统的行为和允许范围有所不同。在未实现该选项的平台上,该选项将被忽略。谨慎使用。


{tos, Integer}

在实现此函数的平台上设置IP_TOS IP 级别选项。不同系统的行为和允许范围有所不同。在未实现该选项的平台上,该选项将被忽略。谨慎使用。


{tclass, Integer}

在实现此函数的平台上设置IPV6_TCLASS IP 级别选项。不同系统的行为和允许范围有所不同。在未实现该选项的平台上,该选项将被忽略。谨慎使用。

除了这些选项之外,还可以使用原始选项规范。原始选项被指定为四元组,以标记 raw 开头,后跟协议级别、选项号和指定为二进制的选项值。这对应于 C 套接字 API 中 setsockopt 调用的第二个、第三个和第四个参数。选项值必须以平台的本机字节序进行编码,并且如果需要结构,则必须遵循特定平台上的结构对齐约定。

使用原始套接字选项需要详细了解当前操作系统和 TCP 堆栈。

例子:

此示例涉及原始选项的使用。考虑一个 Linux 系统,您希望在堆栈中的协议级别 IPPROTO_TCP 上设置选项 TCP_LINGER2。您知道在这个特定的系统上它默认为 60(秒),但您希望针对特定套接字将其降低到 30。 inet 未明确支持选项 TCP_LINGER2,但您知道协议级别转换为数字 6,选项编号转换为数字 8,并且该值将指定为 32 位整数。您可以使用此代码行为名为 Sock 的套接字设置选项:

inet:setopts(Sock,[{raw,6,8,<<30:32/native>>}]),

因为如果指定的选项超出范围,堆栈会默默地丢弃许多选项;检查原始选项是否被接受可能是个好主意。以下代码将值放入变量TcpLinger2:

{ok,[{raw,6,8,<<TcpLinger2:32/native>>}]}=inet:getopts(Sock,[{raw,6,8,4}]),

诸如这些示例之类的代码本质上是不可移植的,即使同一平台上同一操作系统的不同版本也可能对这种选项操作做出不同的响应。小心使用。

请注意,TCP/IP 套接字的默认选项可以使用本手册页开头提到的内核配置参数进行更改。

相关用法


注:本文由纯净天空筛选整理自erlang.org大神的英文原创作品 setopts(Socket, Options) -> ok | {error, posix()}。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。