檢視原始碼 gen_udp (核心 v10.2)

UDP sockets 的介面。

此模組提供透過 UDP 協定 sockets 通訊的函式。

注意

建立 sockets 的函式可以接受一個可選的選項;{inet_backend, Backend},如果指定,則必須是第一個選項。這會選擇平台 socket API 的實作後端。

這是一個暫時性的選項,未來版本將會被忽略。

預設值為 Backend = inet,這會選擇傳統的 inet_drv.c 驅動程式。另一個選擇是 Backend = socket,這會選擇新的 socket 模組及其 NIF 實作。

當節點以應用程式 kernel 的組態變數 inet_backend 啟動時,可以變更系統預設值。

對於 gen_udpinet_backend = socket,我們嘗試盡可能地「相容」,但有時這是不可能的。以下列出 inet 後端 inet(預設)與 socket 行為不同的情況:

  • 選項 read_packets 目前被忽略

  • Windows 需要 sockets(網域 = inet | inet6)被綁定。

    目前,在 Windows 上以 inet_backend = socket 建立的所有 sockets 都會被綁定。如果使用者未提供位址,gen_udp 將嘗試自行「找出」一個位址。

摘要

類型

此 IPv6 多點傳送介面索引(整數)。

IP 多點傳送成員。

open/1,2 傳回的 socket。

函式

關閉 UDP socket。

連線 UDP socket。

連線 UDP socket。

變更 socket 的控制程序(擁有者)。

等同於 open(Port, [])

開啟 UDP socket。

被動模式下從 socket 接收封包。

在已連線的 UDP socket 上傳送封包。

將 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 元組形式。在支援 3 元組變體的平台上,「ifindex」預設為零 (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 傳回的 socket。

函式

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

關閉 UDP socket。

連結到此函式

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 socket。

連線 UDP socket 僅表示儲存指定的(目的地)socket 位址,如 SockAddr 所指定,以便系統知道要將資料傳送到何處。

當 socket「連線」時,傳送資料報時不必指定目的地位址。也就是說,可以使用 send/2

這也表示 socket 只會從連線的位址接收資料。其他訊息會在到達時被 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 socket。

請參閱 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().

變更 socket 的控制程序(擁有者)。

將新的控制程序 Pid 指派給 Socket。控制程序是 socket 將訊息傳送到的程序。如果此函式是從目前控制程序以外的任何其他程序呼叫,則會傳回 {error, not_owner}

如果由 Pid 識別的程序不是現有的本機 pid/0,則會傳回 {error, badarg}。在某些情況下,當 Socket 在此函式執行期間關閉時,也可能傳回 {error, badarg}

如果 socket 處於主動模式,此函式會將呼叫者信箱中來自 socket 的任何訊息傳輸到新的控制程序。

如果任何其他程序在傳輸期間與 socket 互動,則可能無法正確運作,訊息可能會保留在呼叫者的信箱中。例如,在傳輸期間變更 sockets 的主動模式可能會導致這種情況。

-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 socket。

建立的 socket 會綁定到 UDP 通訊埠號碼 Port。如果 Port == 0,則底層 OS 會指派一個可用的(臨時)UDP 通訊埠;請使用 inet:port/1 來擷取它。

呼叫此函式的程序會變成 Socket 的控制程序(socket 擁有者)。

UDP socket 選項

  • 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} - 如果 socket 未使用 gen_udp 以某種方式開啟,請使用此選項傳遞其檔案描述符。如果 Port 未設定為 0,和/或 {ip, ip_address()} 與此選項結合使用,則 fd 會在開啟後綁定到指定的介面和通訊埠。如果未指定這些選項,則假設 fd 已適當地綁定。

  • inet6 - 設定 IPv6 的 socket。

  • inet - 設定 IPv4 的 socket。

  • local - 設定 Unix 網域 Socket。請參閱 inet:local_address/0

  • {udp_module, module()} - 覆寫使用的回呼模組。IPv4 預設為 inet_udp,IPv6 預設為 inet6_udp

  • {multicast_if, Address} - 設定多點傳送 socket 的本機裝置。

  • {multicast_loop, true | false} - 當 true 時,傳送的多點傳送封包會迴路傳回本機 sockets。

  • {multicast_ttl, Integer} - 選項 multicast_ttl 會變更傳出多點傳送資料報的存活時間 (TTL),以控制多點傳送的範圍。

    TTL 為 1 的資料報不會轉送到本機網路之外。預設值為 1

  • {add_membership, {MultiAddress, InterfaceAddress}} - 加入多點傳送群組。

  • {drop_membership, {MultiAddress, InterfaceAddress}} - 離開多點傳送群組。

  • option/0 - 請參閱 inet:setopts/2

UDP 封包會使用此 socket 與 send(Socket, ...) 傳送。當 UDP 封包到達 Socket 的 UDP 通訊埠,且 socket 處於主動模式時,封包會以訊息的形式傳遞到控制程序(socket 擁有者)。

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

PeerIPPeerPort 是傳送 Packet 的位址。Packet 是一個位元組清單 ([byte/0],如果選項 list 為作用中,而如果選項 binary 為作用中,則為 binary/0(它們是互斥的)。

只有在任何 socket 選項 recvtosrecvtclassrecvttl 啟用時,訊息才會包含 AncData 欄位。

當一個處於 {active, N} 模式(詳見 inet:setopts/2)的 socket,轉換為被動 ({active, false}) 模式(N 遞減至 0)時,控制程序會收到以下形式的訊息通知

{udp_passive, Socket}

如果作業系統協定堆疊回報 socket 錯誤,以下訊息會被傳送到控制程序

{udp_error, Socket, Reason}

Reason 主要是一個 POSIX 錯誤代碼

如果 socket 處於被動模式(而非主動模式),接收到的資料可以使用 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().

被動模式下從 socket 接收封包。

Timeout 指定以毫秒為單位的逾時時間。

如果任何 socket 選項 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 socket 上傳送封包。

要連線 UDP socket,請使用 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 可以是主機名稱或 socket 位址,而 Port 可以是埠號或服務名稱原子。這些會被解析為 Destination,然後此函式等同於底下的 send(Socket, Destination, [], Packet)

使用引數 DestinationAncData (自 OTP 22.1 起)

傳送封包至指定的 Destination,並帶有輔助資料 AncData

注意

輔助資料 AncData 包含針對此單一訊息覆蓋 socket 預設選項的選項,此操作可能不被所有平台支援,如果無法支援,則會返回 {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)