查看源代码 gen_udp (内核 v10.2)

UDP 套接字的接口。

此模块提供通过 UDP 协议套接字进行通信的函数。

注意

创建套接字的函数可以采用可选选项;{inet_backend, 后端},如果指定,则必须是第一个选项。这将选择平台套接字 API 的实现后端。

这是一个临时选项,将在未来的版本中被忽略。

默认值为 后端 = inet,它选择传统的 inet_drv.c 驱动程序。另一个选择是 后端 = socket,它选择新的 socket 模块及其 NIF 实现。

当节点启动时,可以使用应用程序 kernel 的配置变量 inet_backend 更改系统默认值。

对于 gen_udpinet_backend = socket,我们尝试尽可能“兼容”,但这有时是不可能的。以下是 inet 后端 inet(默认)和 socket 的行为不同的情况列表

  • 选项 read_packets 当前被忽略

  • Windows 要求套接字(域 = inet | inet6)被绑定。

    当前,在 Windows 上使用 inet_backend = socket 创建的所有套接字都将被绑定。如果用户未提供地址,则 gen_udp 将尝试自行“找出”一个地址。

摘要

类型

IPv6 此多播接口索引(一个整数)。

IP 多播成员资格。

open/1,2 返回的套接字。

函数

关闭 UDP 套接字。

连接 UDP 套接字。

连接 UDP 套接字。

更改套接字的控制进程(所有者)。

等效于 open(Port, [])

打开 UDP 套接字。

被动模式下从套接字接收数据包。

在已连接的 UDP 套接字上发送数据包。

将 UDP 数据包发送到指定的目标。

将带有辅助数据的数据包发送到指定的目标。

类型

-type ip6_membership() :: {MultiAddress :: inet:ip6_address(), IfIndex :: integer()}.
-type ip6_multicast_if() :: integer().

IPv6 此多播接口索引(一个整数)。

-type ip_membership() ::
          {MultiAddress :: inet:ip4_address(), Interface :: inet:ip4_address()} |
          {MultiAddress :: inet:ip4_address(), Address :: inet:ip4_address(), IfIndex :: integer()}.

IP 多播成员资格。

并非所有平台都支持 3 元组形式。“ifindex”在支持 3 元组变体的平台上默认为零 (0)。

-type ip_multicast_if() :: inet:ip4_address().
-type membership() :: ip_membership() | ip6_membership().
-type multicast_if() :: ip_multicast_if() | ip6_multicast_if().
-type open_option() ::
          {ip, inet:socket_address()} |
          {fd, non_neg_integer()} |
          {ifaddr, socket:sockaddr_in() | socket:sockaddr_in6() | inet:socket_address()} |
          inet:address_family() |
          {port, inet:port_number()} |
          {netns, file:filename_all()} |
          {bind_to_device, binary()} |
          option().
-type option() ::
          {active, true | false | once | -32768..32767} |
          {add_membership, membership()} |
          {broadcast, boolean()} |
          {buffer, non_neg_integer()} |
          {debug, boolean()} |
          {deliver, port | term} |
          {dontroute, boolean()} |
          {drop_membership, membership()} |
          {exclusiveaddruse, boolean()} |
          {header, non_neg_integer()} |
          {high_msgq_watermark, pos_integer()} |
          {low_msgq_watermark, pos_integer()} |
          {mode, list | binary} |
          list | binary |
          {multicast_if, multicast_if()} |
          {multicast_loop, boolean()} |
          {multicast_ttl, non_neg_integer()} |
          {priority, non_neg_integer()} |
          {raw, Protocol :: non_neg_integer(), OptionNum :: non_neg_integer(), ValueBin :: binary()} |
          {read_packets, non_neg_integer()} |
          {recbuf, non_neg_integer()} |
          {reuseaddr, boolean()} |
          {reuseport, boolean()} |
          {reuseport_lb, boolean()} |
          {sndbuf, non_neg_integer()} |
          {tos, non_neg_integer()} |
          {tclass, non_neg_integer()} |
          {ttl, non_neg_integer()} |
          {recvtos, boolean()} |
          {recvtclass, boolean()} |
          {recvttl, boolean()} |
          {ipv6_v6only, boolean()}.
-type option_name() ::
          active | broadcast | buffer | debug | deliver | dontroute | exclusiveaddruse | header |
          high_msgq_watermark | low_msgq_watermark | mode | multicast_if | multicast_loop |
          multicast_ttl | priority |
          {raw,
           Protocol :: non_neg_integer(),
           OptionNum :: non_neg_integer(),
           ValueSpec :: (ValueSize :: non_neg_integer()) | (ValueBin :: binary())} |
          read_packets | recbuf | reuseaddr | reuseport | reuseport_lb | sndbuf | tos | tclass | ttl |
          recvtos | recvtclass | recvttl | pktoptions | ipv6_v6only.
-type socket() :: inet:socket().

open/1,2 返回的套接字。

函数

-spec close(Socket) -> ok when Socket :: socket().

关闭 UDP 套接字。

链接到此函数

connect(Socket, SockAddr)

查看源代码 (自 OTP 24.3 起)
-spec connect(Socket, SockAddr) -> ok | {error, Reason}
                 when
                     Socket :: socket(),
                     SockAddr :: socket:sockaddr_in() | socket:sockaddr_in6(),
                     Reason :: inet:posix().

连接 UDP 套接字。

连接 UDP 套接字仅表示存储指定的(目标)套接字地址(如 SockAddr 所指定),以便系统知道将数据发送到哪里。

当套接字“连接”后,发送数据报时无需指定目标地址。即可以使用 send/2

这也意味着套接字只会接收来自已连接地址的数据。其他消息会在到达时被 OS 协议栈丢弃。

链接到此函数

connect(Socket, Address, Port)

查看源代码 (自 OTP 24.3 起)
-spec connect(Socket, Address, Port) -> ok | {error, Reason}
                 when
                     Socket :: socket(),
                     Address :: inet:socket_address() | inet:hostname(),
                     Port :: inet:port_number(),
                     Reason :: inet:posix().

连接 UDP 套接字。

请参阅 connect/2

使用此函数,目标使用单独的 AddressPort 参数指定,其中 Address 可以是 IP 地址主机名

链接到此函数

controlling_process(Socket, Pid)

查看源代码
-spec controlling_process(Socket, Pid) -> ok | {error, Reason}
                             when
                                 Socket :: socket(),
                                 Pid :: pid(),
                                 Reason :: closed | not_owner | badarg | inet:posix().

更改套接字的控制进程(所有者)。

将新的控制进程 Pid 分配给 Socket。控制进程是套接字将消息发送到的进程。如果此函数由当前控制进程之外的任何其他进程调用,则返回 {error, not_owner}

如果由 Pid 标识的进程不是现有本地 pid/0,则返回 {error, badarg}。当 Socket 在此函数执行期间关闭时,在某些情况下也可能返回 {error, badarg}

如果套接字处于活动模式,此函数会将调用者邮箱中套接字的任何消息传输到新的控制进程。

如果在传输期间任何其他进程与套接字交互,它可能无法正常工作,消息可能会保留在调用者的邮箱中。例如,在传输期间更改套接字的活动模式可能会导致这种情况。

-spec open(Port) -> {ok, Socket} | {error, Reason}
              when Port :: inet:port_number(), Socket :: socket(), Reason :: system_limit | inet:posix().

等效于 open(Port, [])

-spec open(Port, Opts) -> {ok, Socket} | {error, Reason}
              when
                  Port :: inet:port_number(),
                  Opts :: [inet:inet_backend() | open_option()],
                  Socket :: socket(),
                  Reason :: system_limit | inet:posix().

打开 UDP 套接字。

创建的套接字绑定到 UDP 端口号 Port。如果 Port == 0,则底层操作系统会分配一个空闲(临时)UDP 端口;使用 inet:port/1 来检索它。

调用此函数的进程成为 Socket 的控制进程(套接字所有者)。

UDP 套接字选项

  • list - 接收到的 Packet 将作为列表传递。

  • binary - 接收到的 Packet 将作为二进制传递。

  • {ip, Address} - 如果本地主机有多个 IP 地址,此选项指定要使用的地址。

  • {ifaddr, Address} - 与 {ip, Address} 相同。

    但是,如果这反而是一个 socket:sockaddr_in/0socket:sockaddr_in6/0,则它优先于先前使用 ip 选项设置的任何值。如果 ip 选项在 ifaddr 选项之后出现,则可以使用它来更新 ifaddr 选项的相应字段(addr 字段)。

  • {fd, integer() >= 0} - 如果套接字在未使用 gen_udp 的情况下以某种方式打开,请使用此选项传递其文件描述符。如果 Port 未设置为 0 和/或 {ip, ip_address()} 与此选项组合,则 fd 将在打开后绑定到指定的接口和端口。如果未指定这些选项,则假定 fd 已被适当绑定。

  • inet6 - 为 IPv6 设置套接字。

  • inet - 为 IPv4 设置套接字。

  • local - 设置 Unix 域套接字。请参阅 inet:local_address/0

  • {udp_module, module()} - 覆盖使用的回调模块。对于 IPv4,默认为 inet_udp,对于 IPv6,默认为 inet6_udp

  • {multicast_if, Address} - 为多播套接字设置本地设备。

  • {multicast_loop, true | false} - 当 true 时,发送的多播数据包会循环回到本地套接字。

  • {multicast_ttl, Integer} - 选项 multicast_ttl 更改传出多播数据报的生存时间 (TTL),以控制多播的范围。

    TTL 为 1 的数据报不会转发到本地网络之外。默认为 1

  • {add_membership, {MultiAddress, InterfaceAddress}} - 加入多播组。

  • {drop_membership, {MultiAddress, InterfaceAddress}} - 离开多播组。

  • option/0 - 请参阅 inet:setopts/2

使用此套接字发送 UDP 数据包使用 send(Socket, ...)。当 UDP 数据包到达 Socket 的 UDP 端口时,并且套接字处于活动模式,数据包将作为消息传递给控制进程(套接字所有者)

{udp, Socket, PeerIP, PeerPort, Packet} % Without ancillary data
{udp, Socket, PeerIP, PeerPort, AncData, Packet} % With ancillary data

PeerIPPeerPort 是发送 Packet 的地址。Packet 是一个字节列表(如果选项 list 处于活动状态,则为 [byte/0],如果选项 binary 处于活动状态,则为 binary/0(它们是互斥的)。

只有当套接字的选项 recvtosrecvtclassrecvttl 中有任何一个处于激活状态时,消息才包含 AncData 字段。

当处于 {active, N} 模式(详情请参阅 inet:setopts/2)的套接字转换为被动 ({active, false}) 模式(N 倒数至 0)时,控制进程会收到如下形式的消息通知

{udp_passive, Socket}

如果操作系统协议栈报告套接字错误,则会将以下消息发送到控制进程

{udp_error, Socket, Reason}

Reason 主要是一个 POSIX 错误代码

如果套接字处于被动模式(而不是主动模式),则可以使用recv/2,3](recv/2) 调用检索接收到的数据。请注意,传入的 UDP 数据包如果长度超过接收缓冲区选项指定的长度,可能会被截断,而不会发出警告。

接收缓冲区选项的默认值为 {recbuf, 8192}

-spec recv(Socket, Length) -> {ok, RecvData} | {error, Reason}
              when
                  Socket :: socket(),
                  Length :: non_neg_integer(),
                  RecvData :: {Address, Port, Packet} | {Address, Port, AncData, Packet},
                  Address :: inet:ip_address() | inet:returned_non_ip_address(),
                  Port :: inet:port_number(),
                  AncData :: inet:ancillary_data(),
                  Packet :: string() | binary(),
                  Reason :: not_owner | inet:posix().

等效于 recv(Socket, Length, infinity)

链接到此函数

recv(Socket, Length, Timeout)

查看源代码
-spec recv(Socket, Length, Timeout) -> {ok, RecvData} | {error, Reason}
              when
                  Socket :: socket(),
                  Length :: non_neg_integer(),
                  Timeout :: timeout(),
                  RecvData :: {Address, Port, Packet} | {Address, Port, AncData, Packet},
                  Address :: inet:ip_address() | inet:returned_non_ip_address(),
                  Port :: inet:port_number(),
                  AncData :: inet:ancillary_data(),
                  Packet :: string() | binary(),
                  Reason :: not_owner | timeout | inet:posix().

被动模式下从套接字接收数据包。

Timeout 指定以毫秒为单位的超时时间。

如果套接字的任何选项 recvtosrecvtclassrecvttl 处于活动状态,则 RecvData 元组包含 AncData 字段,否则不包含。

链接到此函数

send(Socket, Packet)

查看源代码 (自 OTP 24.3 起)
-spec send(Socket, Packet) -> ok | {error, Reason}
              when Socket :: socket(), Packet :: iodata(), Reason :: not_owner | inet:posix().

在已连接的 UDP 套接字上发送数据包。

要连接 UDP 套接字,请使用 connect/2connect/3

链接到此函数

send(Socket, Destination, Packet)

查看源代码 (自 OTP 22.1 起)
-spec send(Socket, Destination, Packet) -> ok | {error, Reason}
              when
                  Socket :: socket(),
                  Destination ::
                      {inet:ip_address(), inet:port_number()} |
                      inet:family_address() |
                      socket:sockaddr_in() |
                      socket:sockaddr_in6(),
                  Packet :: iodata(),
                  Reason :: not_owner | inet:posix().

等效于 send(Socket, Destination, [], Packet)

-spec send(Socket, Host, Port, Packet) -> ok | {error, Reason}
              when
                  Socket :: socket(),
                  Host :: inet:hostname() | inet:ip_address(),
                  Port :: inet:port_number() | atom(),
                  Packet :: iodata(),
                  Reason :: not_owner | inet:posix();
          (Socket, Destination, AncData, Packet) -> ok | {error, Reason}
              when
                  Socket :: socket(),
                  Destination ::
                      {inet:ip_address(), inet:port_number()} |
                      inet:family_address() |
                      socket:sockaddr_in() |
                      socket:sockaddr_in6(),
                  AncData :: inet:ancillary_data(),
                  Packet :: iodata(),
                  Reason :: not_owner | inet:posix();
          (Socket, Destination, PortZero, Packet) -> ok | {error, Reason}
              when
                  Socket :: socket(),
                  Destination :: {inet:ip_address(), inet:port_number()} | inet:family_address(),
                  PortZero :: inet:port_number(),
                  Packet :: iodata(),
                  Reason :: not_owner | inet:posix().

将 UDP 数据包发送到指定的目标。

使用参数 HostPort

参数 Host 可以是主机名或套接字地址,Port 可以是端口号或服务名称原子。这些将解析为 Destination,然后此函数等效于 send(Socket, Destination, [], Packet),如下所示。

使用参数 DestinationAncData (自 OTP 22.1 起)

将数据包发送到指定的 Destination,并带有辅助数据 AncData

注意

辅助数据 AncData 包含此单个消息的选项,这些选项会覆盖套接字的默认选项,此操作可能并非所有平台都支持,如果不支持,则返回 {error, einval}。使用多个辅助数据项类型也可能不受支持。AncData =:= [] 始终受支持。

使用参数 DestinationPortZero (自 OTP 22.1 起)

将数据包发送到指定的 Destination。由于 Destination 是一个完整的地址,PortZero 是冗余的,必须为 0

这是一个遗留子句,主要用于 Destination = {local, Binary},其中 PortZero 是多余的。等效于 send(Socket, Destination, [], Packet),就在这里之上。

链接到此函数

send(Socket, Host, Port, AncData, Packet)

查看源代码 (自 OTP 22.1 起)
-spec send(Socket, Host, Port, AncData, Packet) -> ok | {error, Reason}
              when
                  Socket :: socket(),
                  Host :: inet:hostname() | inet:ip_address() | inet:local_address(),
                  Port :: inet:port_number() | atom(),
                  AncData :: inet:ancillary_data(),
                  Packet :: iodata(),
                  Reason :: not_owner | inet:posix().

将带有辅助数据的数据包发送到指定的目标。

关于 HostPort,等效于 send(Socket, Host, Port, Packet),关于辅助数据 AncData,也等效于 send(Socket, Destination, AncData, Packet)