Using `net_adm` modules functions for localhost development nodes - erlang

I'm poking around with the net_adm module and can't seem to get any joy working with localhost nodes. My machine is named:
> hostname
walden
and I start up a few local short-named nodes:
> erl -sname one -setcookie monster
Erlang R16B (erts-5.10.1) [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V5.10.1 (abort with ^G)
(one#walden)1>
and
> erl -sname two -setcookie monster
Erlang R16B (erts-5.10.1) [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V5.10.1 (abort with ^G)
(two#walden)1>
So far, so good.
(two#walden)1> net_adm:names().
{ok,[{"two",63489},{"one",63491}]}
(two#walden)2> net_adm:localhost().
"walden"
(two#walden)3> net_adm:names().
{ok,[{"two",63489},{"one",63491}]}
Both of the local nodes are registered but they aren't connected, which is expected.
(two#walden)4> nodes().
[]
Back on node one:
(one#walden)1> net_adm:names(two).
{error,nxdomain}
(one#walden)2> net_adm:names('two#walden').
{error,nxdomain}
(one#walden)3> net_adm:dns_hostname(two).
{error,two}
(one#walden)4> net_adm:dns_hostname(two#walden).
{error,two#walden}
Erlang correctly identifies my localhost as walden but dns_hostname/1 returns an error. Back on two:
(two#walden)5> net_adm:ping(one#walden).
pong
(two#walden)6> nodes().
[one#walden]
and
(one#walden)5> nodes().
[two#walden]
Okay, bummer. It'd be really convenient to use a .hosts.erlang file for localhost development nodes--via net_adm:worlds/0--but it seems like I'm stuck a bit. Am I missing something or doing something glaringly wrong? Could my overall system be misconfigured?

You need to pass a hostname to names and dns_hostname, not a node name. It looks like your nodes are already connected to me, since the other shows up when you run nodes().

Related

How can I send a message to another node?

I want to implement a simple chat room in which two nodes can send message to each other synchronous. There is not a node that plays a role of server.
Can I use ! to send a message to another node, if i have the pid of the process on this node by function of spawn(Node,Module,Fun,Args)?
You can send to processes at another node just the same you would do with a process local to the same node. The trick is of course you need to have the process id. But you can also send to a process registered at another node by using the tuple {RegisteredName, NodeName}, e.g.
register(a, self()), {a, node()} ! foo.
will send a message to yourself.The same syntax works across nodes.
A more elaborate example
In the first shell:
erl -sname one
Erlang R15B01 (erts-5.9.1) [source] [smp:8:8] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.1 (abort with ^G)
one#grannysmith)1> (one#grannysmith)1> register(hello_server, self()).
(one#grannysmith)2>
true
In the second shell:
erl -sname two
Erlang R15B01 (erts-5.9.1) [source] [smp:8:8] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.1 (abort with ^G)
two#grannysmith)1> (one#grannysmith)1> {hello_server, 'one#grannysmith'} ! good_day.
good_day
(two#grannysmith)2>
And again in the first shell:
(one#grannysmith)2> flush().
Shell got good_day
ok

How to know the id of a node in erlang

When we run a node() command we get the pid of the node. In the format <0.X.0> if we are on the same node and we get a result of the form < X.Y.0> when running the same command from some other node. I want to know how to get the value X from < X.Y.0> on the same node.
Do you mean the integer value of the node part of a pid or the name of the node. For the name there is the BIF node/1 which returns the name of the node to which that pid refers. So
node(self()) ==> 'mynode#my_host.com'
node(RemotePid) ==> 'remote_node#remote_host.com'
It also works for ports and refs which are node specific. The value of the first field is always 0 for the current node and the value will vary for remote nodes. The values in references to the same remote node will be different on different nodes.
N.B. What the representation of a pid <X.Y.Z> actually means is not defined so don't depend too much on it. Although it is unlikely to change.
This definitely doesn't make sens. <0.X.0> is your local Pid, <D.X.0> - distributed variant, where D is a node's number. More information about Pid strcuture. But D will be different for different nodes. So locally you can't get this information.
Off course, you can implement special RPC call, that will return to caller his (caller's) distributed Pid. But results will differ in answers. To ensure this, try simple:
Start three different nodes and register shell as self.
First
erl -sname one
Erlang R15B01 (erts-5.9.1) [source] [64-bit] [smp:8:8] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.1 (abort with ^G)
(one#Alexeys-MacBook-Pro)1> node().
'one#Alexeys-MacBook-Pro'
(one#Alexeys-MacBook-Pro)2> register(shell, self()).
true
Second
erl -sname two
Erlang R15B01 (erts-5.9.1) [source] [64-bit] [smp:8:8] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.1 (abort with ^G)
(two#Alexeys-MacBook-Pro)1> node().
'two#Alexeys-MacBook-Pro'
(two#Alexeys-MacBook-Pro)2> register(shell, self()).
true
Third
erl -sname three
Erlang R15B01 (erts-5.9.1) [source] [64-bit] [smp:8:8] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9.1 (abort with ^G)
(three#Alexeys-MacBook-Pro)1> node().
'three#Alexeys-MacBook-Pro'
(three#Alexeys-MacBook-Pro)2> register(shell, self()).
true
Now return to node one, and try
(one#Alexeys-MacBook-Pro)6> net_kernel:connect('two#Alexeys-MacBook-Pro').
true
(one#Alexeys-MacBook-Pro)7> net_kernel:connect('threeAlexeys-MacBook-Pro').
true
(one#Alexeys-MacBook-Pro)8> {shell, 'two#Alexeys-MacBook-Pro'} ! {hello, from, self()}.
{hello,from,<0.147.0>}
(one#Alexeys-MacBook-Pro)82> {shell, 'three#Alexeys-MacBook-Pro'} ! {hello, from, self()}.
{hello,from,<0.147.0>}
Check result on nodes two
(two#Alexeys-MacBook-Pro)3> flush().
Shell got {hello,from,<6767.147.0>}
ok
and tree
(three#Alexeys-MacBook-Pro)3> flush().
Shell got {hello,from,<6803.147.0>}
ok
As you can see, first part of Pid differs: <6767.147.0> and <6803.147.0>.

erlang gen_tcp:connect/3 not working with rpc:call/4, anyone knows why?

Could not solve this by myself
launched a new node A with ssh command
started a new node B
gen_tcp:connect/3 works on B, but rpc:call(B,gen_tcp,connect,Params) not works.
Both nodes are running on local laptop
and one node returns ok and the other node returns error.
I don't understand.
Anyone knows why?
~ $ssh allen#127.0.0.1 'erl -name loadtest#127.0.0.1 -detached -setcookie loadtest'
~ $erl -name allen#127.0.0.1 -setcookie loadtest
Erlang R14B03 (erts-5.8.4) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.8.4 (abort with ^G)
(allen#127.0.0.1)1> gen_tcp:connect("www.google.com",80,[]).
{ok,#Port<0.630>}
(allen#127.0.0.1)2> rpc:call('loadtest#127.0.0.1',gen_tcp,connect,["www.google.com",80,[]]).
{error,nxdomain}

Erlang ping node problem

I made in erlang shell:
1> node().
nonode#nohost
But
2> net_adm:ping(node()).
pang
Why? What's problem? Why not pong?
Thank you.
You didn't start Erlang with -name or -sname, which means that the distribution subsystem was not started. Try this:
$ erl -sname mynode
Erlang R14B02 (erts-5.8.3) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.8.3 (abort with ^G)
(mynode#foobar)1> node().
mynode#foobar
(mynode#foobar)2> net_adm:ping(node()).
pong
I am not 100% sure, but You started erl without "-name" oder "-sname". I believe net_adm:ping/1 only works in a distributed mode.
If you are trying to ping an erlang node but getting a pang.
Check the cookie with erlang:get_cookie() it will be some random string set the cookie of another node with erlang:set_cookie(Node, Cookie) or you could pass the cookie to the flag -setcookie
for example:
(foo#earth) erlang:get_cookie().
ASYRQKVNIFHWIIJQZIYN
(foo#earth) erlang:set_cookie(node(), 'secret cookie').
true
net:ping('mongooseim#localhost').
pong
Check out the docs

Accessing a Mnesia node from another Erlang shell while it is running

What is the best practice to accessing a single running mnesia node from another Erlang shell to only view data in the tables?
I tried opening two shells and pointing them to the same mnesia directory location which I realized was a very bad idea after finding this in the documentation.
-mnesia dir Directory. The name of the directory where all Mnesia data is stored. The name of the directory must be unique for the current node. Two nodes may, under no circumstances, share the same Mnesia directory. The results are totally unpredictable.
I think that easiest way is joining to remote shell. Just start erl with -remsh Node parameter
$ erl -sname foo
Erlang R13B04 (erts-5.7.5) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.7.5 (abort with ^G)
(foo#hynek-notebook)1>
Another terminal:
$ erl -sname bar -remsh 'foo#hynek-notebook'
Erlang R13B04 (erts-5.7.5) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.7.5 (abort with ^G)
(foo#hynek-notebook)1>
Another option is use powerful job control capability of erl (Press ^G)
$ erl -sname bar
Erlang R13B04 (erts-5.7.5) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.7.5 (abort with ^G)
(bar#hynek-notebook)1>
User switch command
--> h
c [nn] - connect to job
i [nn] - interrupt job
k [nn] - kill job
j - list all jobs
s [shell] - start local shell
r [node [shell]] - start remote shell
q - quit erlang
? | h - this message
--> r 'foo#hynek-notebook'
--> j
1 {shell,start,[init]}
2* {'foo#hynek-notebook',shell,start,[]}
--> c
Eshell V5.7.5 (abort with ^G)
(foo#hynek-notebook)1>
User switch command
--> j
1 {shell,start,[init]}
2* {'foo#hynek-notebook',shell,start,[]}
--> c 1
(bar#hynek-notebook)1>
Note that you have to press Enter to show shell prompt if you are switching back to existing one.

Resources