2 套接字使用
2.1 介绍
套接字接口(模块)基本上是在操作系统套接字接口之上的“薄”层。假定,除非您有特殊需求,否则 gen_[tcp|udp|sctp] 应该足够(当它们可用时)。
请注意,仅仅因为我们有一个已记录和描述的选项,并不意味着操作系统支持它。因此,建议用户阅读平台特定文档以了解所使用的选项。
异步调用
某些函数允许进行异步调用(accept/2,connect/3,recv/3,4,recvfrom/3,4,recvmsg/2,3,5,send/3,4,sendmsg/3,4 和 sendto/4,5)。这可以通过将 Timeout 参数设置为 nowait 来实现。例如,如果调用 recv/3 函数,将 Timeout 设置为 nowait(即 recv(Sock, 0, nowait)),而实际上没有要读取的数据,它将返回
- 在 Unix 上
-
{select, SelectInfo}
SelectInfo 包含 SelectHandle.
- 在 Windows 上
-
{completion, CompletionInfo}
CompletionInfo 包含 CompletionHandle.
当数据最终到达时,将向调用者发送“select”或“completion”消息
- 在 Unix 上
-
{'$socket', socket(), select, SelectHandle}
然后,调用者可以再次调用 recv 函数,现在可以预期数据。
请注意,所有其他用户都将被锁定,直到“当前用户”调用了该函数(本例中为 recv)。因此,要么立即调用该函数,要么cancel。
- 在 Windows 上
-
{'$socket', socket(), completion, {CompletionHandle, CompletionStatus}}
CompletionStatus 包含操作(读取)的结果。
用户还必须准备好接收 abort 消息
- {'$socket', socket(), abort, Info}
如果操作由于任何原因被中止(例如,如果套接字被“其他人”关闭)。Info 部分包含中止原因(在本例中,套接字已关闭 Info = {SelectHandle, closed})。
“socket”消息的一般形式是
- {'$socket', Sock :: socket(), Tag :: atom(), Info :: term()}
其中 Info 的格式是 Tag 的函数
标签 | Info 值类型 |
select | select_handle() |
completion | {completion_handle(), CompletionStatus} |
abort | {select_handle(), Reason :: term()} |
select_handle() 与在 SelectInfo 中返回的相同。
completion_handle() 与在 CompletionInfo 中返回的相同。
2.2 套接字注册表
套接字注册表是我们要跟踪套接字的方式。有两个函数可用于交互:socket:number_of/0 和 socket:which_sockets/1。
在动态创建和删除许多套接字的系统中,它(套接字注册表)可能会成为瓶颈。对于此类系统,有几种方法可以控制套接字注册表的用法。
首先,可以通过从源代码构建 OTP 时使用两个配置选项来影响全局默认值
--enable-esock-socket-registry (default) | --disable-esock-socket-registry
其次,可以通过在启动 erlang 之前设置环境变量 ESOCK_USE_SOCKET_REGISTRY(布尔值)来影响全局默认值。
第三,可以通过调用函数 use_registry/1 来在运行时更改全局默认值。
最后,可以通过在创建套接字时(使用 open/2 和 open/4)在它们的 Opts 参数中提供属性 use_registry(布尔值)来覆盖全局默认值(这会影响该特定套接字)。
2.3 套接字选项
级别 otp 的选项
选项名称 | 值类型 | 设置 | 获取 | 其他要求和注释 |
assoc_id | integer() | 否 | 是 | type = seqpacket,protocol = sctp,是一个关联 |
debug | boolean() | 是 | 是 | 无 |
iow | boolean() | 是 | 是 | 无 |
controlling_process | pid() | 是 | 是 | 无 |
rcvbuf | default | pos_integer() | {pos_integer(), pos_ineteger()} | 是 | 是 | 元组格式在 Windows 上不允许。'default' 仅对 set 有效。元组形式仅对类型 'stream' 和协议 'tcp' 有效。 |
rcvctrlbuf | default | pos_integer() | 是 | 是 | default 仅对 set 有效 |
sndctrlbuf | default | pos_integer() | 是 | 是 | default 仅对 set 有效 |
fd | integer() | 否 | 是 | 无 |
use_registry | boolean() | 否 | 是 | 当套接字创建时,通过调用 open/2 或 open/4 设置该值。 |
级别 socket 的选项
选项名称 | 值类型 | 设置 | 获取 | 其他要求和注释 |
acceptconn | boolean() | 否 | 是 | 无 |
bindtodevice | string() | 是 | 是 | 在 Linux 3.8 之前,可以设置此套接字选项,但不能获取。仅适用于某些套接字类型(例如 inet)。如果设置为空值,则绑定将被删除。 |
broadcast | boolean() | 是 | 是 | type = dgram |
bsp_state | map() | 否 | 是 | 仅限 Windows |
debug | integer() | 是 | 是 | 可能需要管理员权限 |
domain | domain() | 否 | 是 | 在 FreeBSD(例如)上不可用 |
dontroute | boolean() | 是 | 是 | 无 |
exclusiveaddruse | boolean() | 是 | 是 | 仅限 Windows |
keepalive | boolean() | 是 | 是 | 无 |
linger | abort | linger() | 是 | 是 | 无 |
maxdg | integer() | 否 | 是 | 仅限 Windows |
max_msg_size | integer() | 否 | 是 | 仅限 Windows |
oobinline | boolean() | 是 | 是 | 无 |
peek_off | integer() | 是 | 是 | domain = local (unix)。目前已禁用,因为在第二次调用 recv([peek]) 时可能会出现无限循环。 |
priority | integer() | 是 | 是 | 无 |
protocol | protocol() | 否 | 是 | 在 (某些) Darwin(例如)上不可用 |
rcvbuf | non_neg_integer() | 是 | 是 | 无 |
rcvlowat | non_neg_integer() | 是 | 是 | 无 |
rcvtimeo | timeval() | 是 | 是 | 此选项通常不受支持(见下文原因)。OTP 必须使用 --enable-esock-rcvsndtime 配置选项显式构建才能使其可用。由于我们的实现是非阻塞的,因此不知道此选项的工作原理或是否会造成故障。因此,我们不建议设置此选项。相反,请对例如 recv/3 函数使用 Timeout 参数。 |
reuseaddr | boolean() | 是 | 是 | 无 |
reuseport | boolean() | 是 | 是 | domain = inet | inet6 |
sndbuf | non_neg_integer() | 是 | 是 | 无 |
sndlowat | non_neg_integer() | 是 | 是 | 在 Linux 上不可更改 |
sndtimeo | timeval() | 是 | 是 | 此选项通常不受支持(见下文原因)。OTP 必须使用 --enable-esock-rcvsndtime 配置选项显式构建才能使其可用。由于我们的实现是非阻塞的,因此不知道此选项的工作原理或是否会造成故障。因此,我们不建议设置此选项。相反,请对例如 send/3 函数使用 Timeout 参数。 |
timestamp | boolean() | 是 | 是 | 无 |
type | type() | 否 | 是 | 无 |
级别 ip 的选项
选项名称 | 值类型 | 设置 | 获取 | 其他要求和注释 |
add_membership | ip_mreq() | 是 | 否 | 无 |
add_source_membership | ip_mreq_source() | 是 | 否 | 无 |
block_source | ip_mreq_source() | 是 | 否 | 无 |
drop_membership | ip_mreq() | 是 | 否 | 无 |
drop_source_membership | ip_mreq_source() | 是 | 否 | 无 |
freebind | boolean() | 是 | 是 | 无 |
hdrincl | boolean() | 是 | 是 | type = raw |
minttl | integer() | 是 | 是 | type = raw |
msfilter | null | ip_msfilter() | 是 | 否 | 无 |
mtu | integer() | 否 | 是 | type = raw |
mtu_discover | ip_pmtudisc() | 是 | 是 | 无 |
multicast_all | boolean() | 是 | 是 | 无 |
multicast_if | any | ip4_address() | 是 | 是 | 无 |
multicast_loop | boolean() | 是 | 是 | 无 |
multicast_ttl | uint8() | 是 | 是 | 无 |
nodefrag | boolean() | 是 | 是 | type = raw |
pktinfo | boolean() | 是 | 是 | type = dgram |
recvdstaddr | boolean() | 是 | 是 | type = dgram |
recverr | boolean() | 是 | 是 | 无 |
recvif | boolean() | 是 | 是 | type = dgram | raw |
recvopts | boolean() | 是 | 是 | type =/= stream |
recvorigdstaddr | boolean() | 是 | 是 | 无 |
recvttl | boolean() | 是 | 是 | type =/= stream |
retopts | boolean() | 是 | 是 | type =/= stream |
router_alert | integer() | 是 | 是 | type = raw |
sendsrcaddr | boolean() | 是 | 是 | 无 |
tos | ip_tos() | 是 | 是 | 某些高优先级级别可能需要超级用户权限 |
transparent | boolean() | 是 | 是 | 需要管理员权限 |
ttl | integer() | 是 | 是 | 无 |
unblock_source | ip_mreq_source() | 是 | 否 | 无 |
级别 ipv6 的选项
选项名称 | 值类型 | 设置 | 获取 | 其他要求和注释 |
addrform | inet | 是 | 否 | 仅适用于已连接并绑定到 v4-mapped-on-v6 地址的 IPv6 套接字 |
add_membership | ipv6_mreq() | 是 | 否 | 无 |
authhdr | boolean() | 是 | 是 | type = dgram | raw,已过时? |
drop_membership | ipv6_mreq() | 是 | 否 | 无 |
dstopts | boolean() | 是 | 是 | type = dgram | raw,需要超级用户权限才能更新 |
flowinfo | boolean() | 是 | 是 | type = dgram | raw,需要超级用户权限才能更新 |
hoplimit | boolean() | 是 | 是 | type = dgram | raw。在某些平台(例如 FreeBSD)上,用于设置以获取 hoplimit 作为控制消息报头。在其他平台(例如 Linux)上,recvhoplimit 被设置以获取 hoplimit。 |
hopopts | boolean() | 是 | 是 | type = dgram | raw,需要超级用户权限才能更新 |
mtu | boolean() | 是 | 是 | 获取:仅在套接字连接后 |
mtu_discover | ipv6_pmtudisc() | 是 | 是 | 无 |
multicast_hops | default | uint8() | 是 | 是 | 无 |
multicast_if | integer() | 是 | 是 | type = dgram | raw |
multicast_loop | boolean() | 是 | 是 | 无 |
recverr | boolean() | 是 | 是 | 无 |
recvhoplimit | boolean() | 是 | 是 | type = dgram | raw。在某些平台(例如 Linux)上,recvhoplimit 被设置以获取 hoplimit |
recvpktinfo | pktinfo | boolean() | 是 | 是 | type = dgram | raw。在某些平台(例如 FreeBSD)上,用于设置以获取 hoplimit 作为控制消息报头。在其他平台(例如 Linux)上,recvhoplimit 被设置以获取 hoplimit。 |
recvtclass | boolean() | 是 | 是 | type = dgram | raw。在某些平台上,用于设置 (=true) 以获取 tclass 控制消息报头。在其他平台上,tclass 被设置以获取 tclass 控制消息报头。 |
router_alert | integer() | 是 | 是 | type = raw |
rthdr | boolean() | 是 | 是 | type = dgram | raw,需要超级用户权限才能更新 |
tclass | integer() | 是 | 是 | 设置与传出数据包关联的流量类别。RFC3542。 |
unicast_hops | default | uint8() | 是 | 是 | 无 |
v6only | boolean() | 是 | 否 | 无 |
级别 tcp 的选项
选项名称 | 值类型 | 设置 | 获取 | 其他要求和注释 |
congestion | string() | 是 | 是 | 无 |
cork | boolean() | 是 | 是 | 在某些平台(例如 FreeBSD)上,'nopush' 不可用。 |
keepcnt | integer() | 是 | 是 | 在 Windows(至少)上,将值设置为大于 255 是非法的。 |
keepidle | integer() | 是 | 是 | 无 |
keepintvl | integer() | 是 | 是 | 无 |
maxseg | integer() | 是 | 是 | 所有平台都不允许设置。 |
nodelay | boolean() | 是 | 是 | 无 |
nopush | boolean() | 是 | 是 | 在某些平台(例如 Linux)上为 'cork'。在 Darwin 上,它的含义与例如 FreeBSD 上不同。 |
级别 udp 的选项
选项名称 | 值类型 | 设置 | 获取 | 其他要求和注释 |
cork | boolean() | 是 | 是 | 无 |
级别 sctp 的选项
选项名称 | 值类型 | 设置 | 获取 | 其他要求和注释 |
associnfo | sctp_assocparams() | 是 | 是 | 无 |
autoclose | non_neg_integer() | 是 | 是 | 无 |
disable_fragments | boolean() | 是 | 是 | 无 |
events | sctp_event_subscribe() | 是 | 否 | 无 |
initmsg | sctp_initmsg() | 是 | 是 | 无 |
maxseg | non_neg_integer() | 是 | 是 | 无 |
nodelay | boolean() | 是 | 是 | 无 |
rtoinfo | sctp_rtoinfo() | 是 | 是 | 无 |