diff options
Diffstat (limited to 'system/doc/tutorial/cnode.xmlsrc')
-rw-r--r-- | system/doc/tutorial/cnode.xmlsrc | 162 |
1 files changed, 125 insertions, 37 deletions
diff --git a/system/doc/tutorial/cnode.xmlsrc b/system/doc/tutorial/cnode.xmlsrc index 293406160f..bcdd1298de 100644 --- a/system/doc/tutorial/cnode.xmlsrc +++ b/system/doc/tutorial/cnode.xmlsrc @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2000</year><year>2013</year> + <year>2000</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -28,19 +28,39 @@ <rev></rev> <file>cnode.xml</file> </header> - <p>This is an example of how to solve the <seealso marker="example">example problem</seealso> by using a C node. Note that a C node would not typically be used for solving a simple problem like this, a port would suffice.</p> + <p>This section outlines an example of how to solve the example + problem in <seealso marker="example">Problem Example</seealso> + by using a C node. Notice that a C node is not typically + used for solving simple problems like this, a port is + sufficient.</p> <section> <title>Erlang Program</title> - <p>From Erlang's point of view, the C node is treated like a normal Erlang node. Therefore, calling the functions <c>foo</c> and <c>bar</c> only involves sending a message to the C node asking for the function to be called, and receiving the result. Sending a message requires a recipient; a process which can be defined using either a pid or a tuple consisting of a registered name and a node name. In this case a tuple is the only alternative as no pid is known.</p> + <p>From Erlang's point of view, the C node is treated like a + normal Erlang node. Thus, calling the functions <c>foo</c> and + <c>bar</c> only involves sending a message to the C node asking + for the function to be called, and receiving the result. Sending + a message requires a recipient, that is, a process that can be + defined using either a pid or a tuple, consisting of a + registered name and a node name. In this case, a tuple is the + only alternative as no pid is known:</p> <pre> {RegName, Node} ! Msg</pre> - <p>The node name <c>Node</c> should be the name of the C node. If short node names are used, the plain name of the node will be <c>cN</c> where <c>N</c> is an integer. If long node names are used, there is no such restriction. An example of a C node name using short node names is thus <c>c1@idril</c>, an example using long node names is <c>[email protected]</c>.</p> - <p>The registered name <c>RegName</c> could be any atom. The name can be ignored by the C code, or it could be used for example to distinguish between different types of messages. Below is an example of what the Erlang code could look like when using short node names. + <p>The node name <c>Node</c> is to be the name of the C node. If + short node names are used, the plain name of the node is + <c>cN</c>, where <c>N</c> is an integer. If long node names are + used, there is no such restriction. An example of a C node name + using short node names is thus <c>c1@idril</c>, an example using + long node names is <c>[email protected]</c>.</p> + <p>The registered name, <c>RegName</c>, can be any atom. The name + can be ignored by the C code, or, for example, be used to + distinguish between different types of messages. An example of + Erlang code using short node names follows: </p> <codeinclude file="complex3.erl" tag="" type="erl"></codeinclude> <p> - When using long node names the code is slightly different as shown in the following example: + When using long node names, the code is slightly different as + shown in the following example: </p> <codeinclude file="complex4.erl" tag="" type="erl"></codeinclude> @@ -50,39 +70,77 @@ <title>C Program</title> <section> - <title>Setting Up the Communication</title> - <p>Before calling any other Erl_Interface function, the memory handling must be initiated.</p> + <title>Setting Up Communication</title> + <p>Before calling any other function in Erl_Interface, the + memory handling must be initiated:</p> <pre> erl_init(NULL, 0);</pre> - <p>Now the C node can be initiated. If short node names are used, this is done by calling <c>erl_connect_init()</c>.</p> + <p>Now the C node can be initiated. If short node names are + used, this is done by calling <c>erl_connect_init()</c>:</p> <pre> erl_connect_init(1, "secretcookie", 0);</pre> - <p>The first argument is the integer which is used to construct the node name. In the example the plain node name will be <c>c1</c>. <br></br> - - The second argument is a string defining the magic cookie. <br></br> - - The third argument is an integer which is used to identify a particular instance of a C node.</p> - <p>If long node node names are used, initiation is done by calling <c>erl_connect_xinit()</c>.</p> + <p>Here:</p> + <list type="bulleted"> + <item>The first argument is the integer used to construct the node name. + <p>In the example, the plain node name is <c>c1</c>.</p></item> + <item>The second argument is a string defining the magic cookie.</item> + <item>The third argument is an integer that is used to identify + a particular instance of a C node.</item> + </list> + <p>If long node node names are used, initiation is done by + calling <c>erl_connect_xinit()</c>:</p> <pre> erl_connect_xinit("idril", "cnode", "[email protected]", &addr, "secretcookie", 0);</pre> - <p>The first three arguments are the host name, the plain node name, and the full node name. The fourth argument is a pointer to an <c>in_addr</c> struct with the IP address of the host, and the fifth and sixth arguments are the magic cookie and instance number.</p> - <p>The C node can act as a server or a client when setting up the communication Erlang-C. If it acts as a client, it connects to an Erlang node by calling <c>erl_connect()</c>, which will return an open file descriptor at success.</p> + <p>Here:</p> + <list type="bulleted"> + <item>The first argument is the host name.</item> + <item>The second argument is the plain node name.</item> + <item>The third argument is the full node name.</item> + <item>The fourth argument is a pointer to an <c>in_addr</c> + struct with the IP address of the host.</item> + <item>The fifth argument is the magic cookie.</item> + <item>The sixth argument is the instance number.</item> + </list> + <p>The C node can act as a server or a client when setting up + the Erlang-C communication. If it acts as a client, it + connects to an Erlang node by calling <c>erl_connect()</c>, + which returns an open file descriptor at success:</p> <pre> fd = erl_connect("e1@idril");</pre> - <p>If the C node acts as a server, it must first create a socket (call <c>bind()</c> and <c>listen()</c>) listening to a certain port number <c>port</c>. It then publishes its name and port number with <c>epmd</c> (the Erlang port mapper daemon, see the man page for <c>epmd</c>).</p> + <p>If the C node acts as a server, it must first create a socket + (call <c>bind()</c> and <c>listen()</c>) listening to a + certain port number <c>port</c>. It then publishes its name + and port number with <c>epmd</c>, the Erlang port mapper + daemon. For details, see the <seealso + marker="erts:epmd">epmd</seealso> manual page in ERTS:</p> <pre> erl_publish(port);</pre> - <p>Now the C node server can accept connections from Erlang nodes.</p> + <p>Now the C node server can accept connections from Erlang nodes:</p> <pre> fd = erl_accept(listen, &conn);</pre> - <p>The second argument to <c>erl_accept</c> is a struct <c>ErlConnect</c> that will contain useful information when a connection has been established; for example, the name of the Erlang node.</p> + <p>The second argument to <c>erl_accept</c> is a struct + <c>ErlConnect</c> which contains useful information when a + connection has been established, for example, the name of the + Erlang node.</p> </section> <section> <title>Sending and Receiving Messages</title> - <p>The C node can receive a message from Erlang by calling <c>erl_receive msg()</c>. This function reads data from the open file descriptor <c>fd</c> into a buffer and puts the result in an <c>ErlMessage</c> struct <c>emsg</c>. <c>ErlMessage</c> has a field <c>type</c> defining which kind of data was received. In this case the type of interest is <c>ERL_REG_SEND</c> which indicates that Erlang sent a message to a registered process at the C node. The actual message, an <c>ETERM</c>, will be in the <c>msg</c> field.</p> - <p>It is also necessary to take care of the types <c>ERL_ERROR</c> (an error occurred) and <c>ERL_TICK</c> (alive check from other node, should be ignored). Other possible types indicate process events such as link/unlink and exit.</p> + <p>The C node can receive a message from Erlang by calling + <c>erl_receive msg()</c>. This function reads data from the + open file descriptor <c>fd</c> into a buffer and puts the + result in an <c>ErlMessage</c> struct <c>emsg</c>. + <c>ErlMessage</c> has a field <c>type</c> defining what kind + of data is received. In this case, the type of interest is + <c>ERL_REG_SEND</c> which indicates that Erlang sent a message + to a registered process at the C node. The actual message, an + <c>ETERM</c>, is in the <c>msg</c> field.</p> + <p>It is also necessary to take care of the types + <c>ERL_ERROR</c> (an error occurred) and <c>ERL_TICK</c> + (alive check from other node, is to be ignored). Other + possible types indicate process events such as link, unlink, + and exit:</p> <pre> while (loop) { @@ -93,7 +151,16 @@ fd = erl_accept(listen, &conn);</pre> loop = 0; /* exit while loop */ } else { if (emsg.type == ERL_REG_SEND) {</pre> - <p>Since the message is an <c>ETERM</c> struct, Erl_Interface functions can be used to manipulate it. In this case, the message will be a 3-tuple (because that was how the Erlang code was written, see above). The second element will be the pid of the caller and the third element will be the tuple <c>{Function,Arg}</c> determining which function to call with which argument. The result of calling the function is made into an <c>ETERM</c> struct as well and sent back to Erlang using <c>erl_send()</c>, which takes the open file descriptor, a pid and a term as arguments.</p> + <p>As the message is an <c>ETERM</c> struct, Erl_Interface + functions can be used to manipulate it. In this case, the + message becomes a 3-tuple, because that is how the Erlang code + is written. The second element will be the pid of the caller + and the third element will be the tuple <c>{Function,Arg}</c> + determining which function to call, and with which argument. + The result of calling the function is made into an + <c>ETERM</c> struct as well and sent back to Erlang using + <c>erl_send()</c>, which takes the open file descriptor, a + pid, and a term as arguments:</p> <pre> fromp = erl_element(2, emsg.msg); tuplep = erl_element(3, emsg.msg); @@ -108,29 +175,30 @@ fd = erl_accept(listen, &conn);</pre> resp = erl_format("{cnode, ~i}", res); erl_send(fd, fromp, resp);</pre> - <p>Finally, the memory allocated by the <c>ETERM</c> creating functions (including <c>erl_receive_msg()</c> must be freed.</p> + <p>Finally, the memory allocated by the <c>ETERM</c> creating + functions (including <c>erl_receive_msg()</c> must be + freed:</p> <pre> erl_free_term(emsg.from); erl_free_term(emsg.msg); erl_free_term(fromp); erl_free_term(tuplep); erl_free_term(fnp); erl_free_term(argp); erl_free_term(resp);</pre> - <p>The resulting C programs can be found in looks like the following examples. First a C node server using short node names.</p> + <p>The following examples show the resulting C programs. + First a C node server using short node names:</p> <codeinclude file="cnode_s.c" type="c"/> - <p>Below follows a C node server using long node names.</p> + <p>A C node server using long node names:</p> <codeinclude file="cnode_s2.c" type="c"/> - <p>And finally we have the code for the C node client.</p> + <p>Finally, the code for the C node client:</p> <codeinclude file="cnode_c.c" type="c"/> </section> </section> <section> <title>Running the Example</title> - <p>1. Compile the C code, providing the paths to the Erl_Interface include files and libraries, and to the <c>socket</c> and <c>nsl</c> libraries.</p> - <p>In R5B and later versions of OTP, the <c>include</c> and <c>lib</c> directories are situated under <c>OTPROOT/lib/erl_interface-VSN</c>, where <c>OTPROOT</c> is the root directory of the OTP installation (<c>/usr/local/otp</c> in the example above) and <c>VSN</c> is the version of the <c>erl_interface</c> application (3.2.1 in the example above). <br></br> - - In R4B and earlier versions of OTP, <c>include</c> and <c>lib</c> are situated under <c>OTPROOT/usr</c>.</p> + <p><em>Step 1.</em> Compile the C code. This provides the paths to + the Erl_Interface include files and libraries, and to the + <c>socket</c> and <c>nsl</c> libraries:</p> <pre> - > <input>gcc -o cserver \\ </input> <input>-I/usr/local/otp/lib/erl_interface-3.2.1/include \\ </input> <input>-L/usr/local/otp/lib/erl_interface-3.2.1/lib \\ </input> @@ -148,11 +216,29 @@ unix> <input>gcc -o cclient \\ </input> <input>-L/usr/local/otp/lib/erl_interface-3.2.1/lib \\ </input> <input>complex.c cnode_c.c \\ </input> <input>-lerl_interface -lei -lsocket -lnsl</input></pre> - <p>2. Compile the Erlang code.</p> + <p>In Erlang/OTP R5B and later versions of OTP, the + <c>include</c> and <c>lib</c> directories are situated under + <c>OTPROOT/lib/erl_interface-VSN</c>, where <c>OTPROOT</c> is + the root directory of the OTP installation + (<c>/usr/local/otp</c> in the recent example) and <c>VSN</c> is + the version of the Erl_Interface application (3.2.1 in the + recent example).</p> + <p>In R4B and earlier versions of OTP, <c>include</c> and + <c>lib</c> are situated under <c>OTPROOT/usr</c>.</p> + <p><em>Step 2.</em> Compile the Erlang code:</p> <pre> unix> <input>erl -compile complex3 complex4</input></pre> - <p>3. Run the C node server example with short node names.</p> - <p>Start the C program <c>cserver</c> and Erlang in different windows. <c>cserver</c> takes a port number as argument and must be started before trying to call the Erlang functions. The Erlang node should be given the short name <c>e1</c> and must be set to use the same magic cookie as the C node, <c>secretcookie</c>.</p> + <p><em>Step 3.</em> Run the C node server example with short node names.</p> + <p>Do as follows:</p> + <list type="bulleted"> + <item>Start the C program <c>cserver</c> and Erlang in + different windows.</item> + <item><c>cserver</c> takes a port number as argument and must + be started before trying to call the Erlang functions.</item> + <item>The Erlang node is to be given the short name <c>e1</c> + and must be set to use the same magic cookie as the C node, + <c>secretcookie</c>:</item> + </list> <pre> unix> <input>cserver 3456</input> @@ -164,7 +250,9 @@ Eshell V4.9.1.2 (abort with ^G) 4 (e1@idril)2> <input>complex3:bar(5).</input> 10</pre> - <p>4. Run the C node client example. Terminate <c>cserver</c> but not Erlang and start <c>cclient</c>. The Erlang node must be started before the C node client is.</p> + <p><em>Step 4.</em> Run the C node client example. Terminate + <c>cserver</c>, but not Erlang, and start <c>cclient</c>. The + Erlang node must be started before the C node client:</p> <pre> unix> <input>cclient</input> @@ -172,7 +260,7 @@ unix> <input>cclient</input> 4 (e1@idril)4> <input>complex3:bar(5).</input> 10</pre> - <p>5. Run the C node server, long node names, example.</p> + <p><em>Step 5.</em> Run the C node server example with long node names:</p> <pre> unix> <input>cserver2 3456</input> |