檢視原始碼 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_udp
與inet_backend = socket
,我們嘗試盡可能地「相容」,但有時這是不可能的。以下列出 inet 後端inet
(預設)與socket
行為不同的情況:
選項 read_packets 目前被忽略。
Windows 需要 sockets(網域 =
inet | inet6
)被綁定。目前,在 Windows 上以
inet_backend = socket
建立的所有 sockets 都會被綁定。如果使用者未提供位址,gen_udp 將嘗試自行「找出」一個位址。
摘要
函式
關閉 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。
-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 協定堆疊捨棄。
-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
。
使用此函式時,目的地會以個別的 Address
和 Port
引數指定,其中 Address
可以是 IP 位址或主機名稱。
-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/0
或socket: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
PeerIP
和 PeerPort
是傳送 Packet
的位址。Packet
是一個位元組清單 ([
byte/0
]
,如果選項 list
為作用中,而如果選項 binary
為作用中,則為 binary/0
(它們是互斥的)。
只有在任何 socket 選項 recvtos
、recvtclass
或 recvttl
啟用時,訊息才會包含 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().
-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 選項 recvtos
、recvtclass
或 recvttl
啟用,則 RecvData
元組包含一個 AncData
欄位,否則不包含。
-spec send(Socket, Packet) -> ok | {error, Reason} when Socket :: socket(), Packet :: iodata(), Reason :: not_owner | inet:posix().
在已連線的 UDP socket 上傳送封包。
-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().
-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 封包傳送至指定的目的地。
使用引數 Host
和 Port
引數 Host
可以是主機名稱或 socket 位址,而 Port
可以是埠號或服務名稱原子。這些會被解析為 Destination
,然後此函式等同於底下的 send(Socket, Destination, [], Packet)
。
使用引數 Destination
和 AncData
(自 OTP 22.1 起)
傳送封包至指定的 Destination
,並帶有輔助資料 AncData
。
注意
輔助資料
AncData
包含針對此單一訊息覆蓋 socket 預設選項的選項,此操作可能不被所有平台支援,如果無法支援,則會返回{error, einval}
。使用多個輔助資料項目類型也可能不被支援。AncData =:= []
永遠被支援。
使用引數 Destination
和 PortZero
(自 OTP 22.1 起)
傳送封包至指定的 Destination
。由於 Destination
是一個完整的位址,因此 PortZero
是多餘的,必須為 0
。
這是一個舊有的子句,主要用於 Destination = {local, Binary}
,其中 PortZero
是多餘的。等同於這裡正上方的 send(Socket, Destination, [], Packet)
。
-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().
將封包連同輔助資料傳送至指定的目的地。
關於 Host
和 Port
,等同於 send(Socket, Host, Port, Packet)
,關於輔助資料 AncData
,則等同於 send(Socket, Destination, AncData, Packet)
。