So there are 2 things here. you are thinking you are talking to an erlang node, but epmd is actually what you’re talking to.
What you actually want is this:
$ iex --name ding --erl '-kernel inet_dist_listen_min 4370 inet_dist_listen_max 4370'
And then use port 4370 in your code above in place of the epmd port.
TLDR follows for those who seek further enlightenment.
epmd
this is the per-node** instance of a name lookup service. You can think of it as zeroconf/bonjour/MDNS for BEAM. this is what listens on port 4369 by default.
I suggest you use wireshark to deconstruct these, they are not really secured and the tool has inbuild epmd debugging already https://wiki.wireshark.org/EPMD
You can also run epmd in foreground debugging mode, like so:
$ epmd -d -d -d
epmd: Fri Mar 8 15:07:14 2019: epmd running - daemon = 0
epmd: Fri Mar 8 15:07:14 2019: try to initiate listening port 4369
epmd: Fri Mar 8 15:07:14 2019: there is already a epmd running at port 4369
Which on my system makes sense, there’s already a running epmd. You can start epmd, then with a single iex non-distributed node, you can manually connect:
iex(1)> :net_kernel.start([:somenode, :shortnames])
{:ok, #PID<0.109.0>}
And your debug epmd spits out this:
epmd -d -d -d
epmd: Fri Mar 8 15:10:56 2019: epmd running - daemon = 0
epmd: Fri Mar 8 15:10:56 2019: try to initiate listening port 4369
epmd: Fri Mar 8 15:10:56 2019: entering the main select() loop
epmd: Fri Mar 8 15:11:01 2019: time in seconds: 1552057861
epmd: Fri Mar 8 15:11:04 2019: Local peer connected
epmd: Fri Mar 8 15:11:04 2019: time in seconds: 1552057864
epmd: Fri Mar 8 15:11:04 2019: opening connection on file descriptor 6
epmd: Fri Mar 8 15:11:04 2019: time in seconds: 1552057864
epmd: Fri Mar 8 15:11:04 2019: got 23 bytes
***** 00000000 00 15 78 e9 30 4d 00 00 05 00 05 00 08 73 6f 6d |..x.0M.......som|
***** 00000010 65 6e 6f 64 65 00 00 |enode..|
epmd: Fri Mar 8 15:11:04 2019: time in seconds: 1552057864
epmd: Fri Mar 8 15:11:04 2019: ** got ALIVE2_REQ
epmd: Fri Mar 8 15:11:04 2019: time in seconds: 1552057864
epmd: Fri Mar 8 15:11:04 2019: registering 'somenode:2', port 59696
epmd: Fri Mar 8 15:11:04 2019: type 77 proto 0 highvsn 5 lowvsn 5
***** active name "somenode#2" at port 59696, fd = 6
***** reg calculated count : 1
***** unreg counter : 0
***** unreg calculated count: 0
epmd: Fri Mar 8 15:11:04 2019: got 4 bytes
***** 00000000 79 00 00 02 |y...|
epmd: Fri Mar 8 15:11:04 2019: ** sent ALIVE2_RESP for "somenode"
epmd: Fri Mar 8 15:11:09 2019: time in seconds: 1552057869
epmd: Fri Mar 8 15:11:14 2019: time in seconds: 1552057874
epmd: Fri Mar 8 15:11:19 2019: time in seconds: 1552057879
epmd: Fri Mar 8 15:11:24 2019: time in seconds: 1552057884
epmd: Fri Mar 8 15:11:29 2019: time in seconds: 1552057889
epmd: Fri Mar 8 15:11:34 2019: time in seconds: 1552057894
epmd: Fri Mar 8 15:11:39 2019: time in seconds: 1552057899
epmd: Fri Mar 8 15:11:44 2019: time in seconds: 1552057904
epmd: Fri Mar 8 15:11:49 2019: time in seconds: 1552057909
epmd: Fri Mar 8 15:11:51 2019: time in seconds: 1552057911
epmd: Fri Mar 8 15:11:51 2019: unregistering 'somenode:2', port 59696
***** reg calculated count : 0
***** old/unused name "somenode#2"
***** unreg counter : 1
***** unreg calculated count: 1
epmd: Fri Mar 8 15:11:51 2019: closing connection on file descriptor 6
There are multiple implementations of epmd, from the upstream source, a couple in go, rust, and also my favourite, this spoofing one in erlang: https://github.com/msantos/spoofed
The other thing is the erlang distribution protocol itself…
To establish a connection between 2 nodes, you need to know the other node’s address. You can obtain this via epmd lookup, or if you are sneaky, you can pre-calculate these and then you don’t need epmd at all. See https://www.erlang-solutions.com/blog/erlang-and-elixir-distribution-without-epmd.html for more details. The first paragraph saves me writing most of this, so go read it.
distribution
As you read the post, now spin up 2 nodes.
$ iex --name ding --erl '-kernel inet_dist_listen_min 4370 inet_dist_listen_max 4370'
Erlang/OTP 21 [erts-10.2.4] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]
Interactive Elixir (1.8.1) - press Ctrl+C to exit (type h() ENTER for help)
$ iex --name dong --erl '-kernel inet_dist_listen_min 4371 inet_dist_listen_max 4371'
Erlang/OTP 21 [erts-10.2.4] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]
Interactive Elixir (1.8.1) - press Ctrl+C to exit (type h() ENTER for help)
Now in one node, you can Node.ping :"dong@...
and run Node.list()
in the other. The reason this is useful is that you can also use wireshark on that port 4370 to see the traffic “exercise left to reader”. If your system is multi-homed you may need to use inet_dist_use_interface {127,0,0,1}
to restrict that to a specific network interface.