2  套接字使用

2  套接字使用

套接字接口(模块)基本上是在操作系统套接字接口之上的“薄”层。假定,除非您有特殊需求,否则 gen_[tcp|udp|sctp] 应该足够(当它们可用时)。

请注意,仅仅因为我们有一个已记录和描述的选项,并不意味着操作系统支持它。因此,建议用户阅读平台特定文档以了解所使用的选项。

某些函数允许进行异步调用(accept/2connect/3recv/3,4recvfrom/3,4recvmsg/2,3,5send/3,4sendmsg/3,4sendto/4,5)。这可以通过将 Timeout 参数设置为 nowait 来实现。例如,如果调用 recv/3 函数,将 Timeout 设置为 nowait(即 recv(Sock, 0, nowait)),而实际上没有要读取的数据,它将返回

{select, SelectInfo}

SelectInfo 包含 SelectHandle.

{completion, CompletionInfo}

CompletionInfo 包含 CompletionHandle.

当数据最终到达时,将向调用者发送“select”或“completion”消息

{'$socket', socket(), select, SelectHandle}

然后,调用者可以再次调用 recv 函数,现在可以预期数据。

请注意,所有其他用户都将被锁定,直到“当前用户”调用了该函数(本例中为 recv)。因此,要么立即调用该函数,要么cancel

{'$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()}

表 2.1:  套接字消息信息值类型

select_handle() 与在 SelectInfo 中返回的相同。

completion_handle() 与在 CompletionInfo 中返回的相同。

套接字注册表是我们要跟踪套接字的方式。有两个函数可用于交互:socket:number_of/0socket:which_sockets/1

在动态创建和删除许多套接字的系统中,它(套接字注册表)可能会成为瓶颈。对于此类系统,有几种方法可以控制套接字注册表的用法。

首先,可以通过从源代码构建 OTP 时使用两个配置选项来影响全局默认值

--enable-esock-socket-registry (default) | --disable-esock-socket-registry

其次,可以通过在启动 erlang 之前设置环境变量 ESOCK_USE_SOCKET_REGISTRY(布尔值)来影响全局默认值。

第三,可以通过调用函数 use_registry/1 来在运行时更改全局默认值。

最后,可以通过在创建套接字时(使用 open/2open/4)在它们的 Opts 参数中提供属性 use_registry(布尔值)来覆盖全局默认值(这会影响特定套接字)。

级别 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/2open/4 设置该值。

表 2.2:  选项级别

级别 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()

表 2.3:  套接字选项

级别 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()

表 2.4:  ip 选项

级别 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()

表 2.5:  ipv6 选项

级别 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 上不同。

表 2.6:   tcp 选项

级别 udp 的选项

选项名称 值类型 设置 获取 其他要求和注释
cork boolean()

表 2.7:   udp 选项

级别 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()

表 2.8:   sctp 选项