A complete re-implementation of the ENet protocol in Erlang/OTP.
NOTE: This is a friendly fork of https://github.com/flambard/enet. This fork is being tested against and adapted to the C implementation of ENet as used by the Godot engine.
The module enet
presents the API of enet.
port_number() = 0..65535
peer_count() = 1..255
channel_count() = 1..255
bytes_per_second() = non_neg_integer()
channels() = #{ non_neg_integer() := pid() }
start_host(Port, ConnectFun, Options) -> {ok, port_number()} | {error, term()}
Port = port_number()
ConnectFun = mfa() | fun((PeerInfo) -> ConnectFunResult)
PeerInfo = map()
ConnectFunResult = {ok, pid()} | {error, term()}
Options = [Option]
Option =
{peer_limit, peer_count()} |
{channel_limit, channel_count()} |
{incoming_bandwidth, bytes_per_second()} |
{outgoing_bandwidth, bytes_per_second()} |
{compression_mode, atom()}
Start a new host. If Port
set to 0
, the port will be dynamically assigned by the underlying operating system. The assigned port is returned.
The ConnectFun
function or MFA tuple will be called when a new peer has started and a connection to a remote peer has been established. This function is expected to spawn a new process and return a pid to which all messages from the new peer will be sent.
stop_host(Port) -> ok
Port = port_number()
Stop a host listening on Port
.
connect_peer(HostPort, IP, RemotePort, ChannelCount) -> {ok, Peer} | {error, atom()}
HostPort = port_number()
IP = string()
RemotePort = port_number()
ChannelCount = channel_count()
Peer = pid()
Start a new peer on the host listening on HostPort
connecting to a remote host on address IP:RemotePort
. The peer process will call ConnectFun
(given to start_host/3) when the handshake has been completed successfully.
disconnect_peer(Peer) -> ok
Peer = pid()
Disconnect Peer
.
disconnect_peer_now(Peer) -> ok
Peer = pid()
Disconnect Peer
immediately without waiting for an ACK from the remote peer.
send_unsequenced(Channel, Data) -> ok
Channel = pid()
Data = iodata()
Send unsequenced data to the remote peer over Channel
.
send_unreliable(Channel, Data) -> ok
Channel = pid()
Data = iodata()
Send unreliable data to the remote peer over Channel
.
send_reliable(Channel, Data) -> ok
Channel = pid()
Data = iodata()
Send reliable data to the remote peer over Channel
.
broadcast_unsequenced(HostPort, ChannelID, Data) -> ok
HostPort = port_number()
ChannelID = integer()
Data = iodata()
Broadcast unsequenced data to all peers connected to HostPort
on ChannelID
.
broadcast_unreliable(HostPort, ChannelID, Data) -> ok
HostPort = port_number()
ChannelID = integer()
Data = iodata()
Broadcast unreliable data to all peers connected to HostPort
on ChannelID
.
broadcast_reliable(HostPort, ChannelID, Data) -> ok
HostPort = port_number()
ChannelID = integer()
Data = iodata()
Broadcast reliable data to all peers connected to HostPort
on ChannelID
.
ListeningPort = 1234,
ConnectFun = fun(PeerInfo) ->
server_supervisor:start_worker(PeerInfo)
end,
Options = [{peer_limit, 8}, {channel_limit, 3}],
{ok, Host} = enet:start_host(ListeningPort, ConnectFun, Options),
...
...
...
enet:stop_host(Host).
ListeningPort = 0, %% Port will be dynamically assigned
ConnectFun = fun(PeerInfo) ->
client_supervisor:start_worker(PeerInfo)
end,
Options = [{peer_limit, 1}, {channel_limit, 3}],
{ok, Host} = enet:start_host(ListeningPort, ConnectFun, Options),
...
...
RemoteHost = "...."
Port = 1234,
ChannelCount = 3
{ok, Peer} = enet:connect_peer(Host, RemoteHost, Port, ChannelCount),
...
...
enet:stop_host(Host).
worker_loop(PeerInfo = #{channels := Channels}, State) ->
...
...
{ok, Channel0} = maps:find(0, Channels),
Data = <<"packet">>,
enet:send_unsequenced(Channel0, Data),
enet:send_unreliable(Channel0, Data),
enet:send_reliable(Channel0, Data),
...
...
worker_loop(PeerInfo, State).
worker_loop(PeerInfo, State) ->
...
...
receive
{enet, ChannelID, #unsequenced{ data = Packet }} ->
%% Handle the Packet
ok;
{enet, ChannelID, #unreliable{ data = Packet }} ->
%% Handle the Packet
ok;
{enet, ChannelID, #reliable{ data = Packet }} ->
%% Handle the Packet
ok
end,
...
...
worker_loop(PeerInfo, State).