Sophie

Sophie

distrib > Fedora > 17 > i386 > by-pkgid > 675c8c8167236dfcf8d66da674f931e8 > files > 133

erlang-doc-R15B-03.3.fc17.noarch.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html xmlns:fn="http://www.w3.org/2005/02/xpath-functions">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="../otp_doc.css" type="text/css">
<title>Erlang -- Ports</title>
</head>
<body bgcolor="white" text="#000000" link="#0000ff" vlink="#ff00ff" alink="#ff0000"><div id="container">
<script id="js" type="text/javascript" language="JavaScript" src="../js/flipmenu/flipmenu.js"></script><script id="js2" type="text/javascript" src="../js/erlresolvelinks.js"></script><script language="JavaScript" type="text/javascript">
            <!--
              function getWinHeight() {
                var myHeight = 0;
                if( typeof( window.innerHeight ) == 'number' ) {
                  //Non-IE
                  myHeight = window.innerHeight;
                } else if( document.documentElement && ( document.documentElement.clientWidth ||
                                                         document.documentElement.clientHeight ) ) {
                  //IE 6+ in 'standards compliant mode'
                  myHeight = document.documentElement.clientHeight;
                } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
                  //IE 4 compatible
                  myHeight = document.body.clientHeight;
                }
                return myHeight;
              }

              function setscrollpos() {
                var objf=document.getElementById('loadscrollpos');
                 document.getElementById("leftnav").scrollTop = objf.offsetTop - getWinHeight()/2;
              }

              function addEvent(obj, evType, fn){
                if (obj.addEventListener){
                obj.addEventListener(evType, fn, true);
                return true;
              } else if (obj.attachEvent){
                var r = obj.attachEvent("on"+evType, fn);
                return r;
              } else {
                return false;
              }
             }

             addEvent(window, 'load', setscrollpos);

             //--></script><div id="leftnav"><div class="innertube">
<img alt="Erlang logo" src="../erlang-logo.png"><br><small><a href="users_guide.html">User's Guide</a><br><a href="../pdf/otp-system-documentation-5.9.3.1.pdf">PDF</a><br><a href="../index.html">Top</a></small><p><strong>Interoperability Tutorial</strong><br><strong>User's Guide</strong><br><small>Version 5.9.3.1</small></p>
<br><a href="javascript:openAllFlips()">Expand All</a><br><a href="javascript:closeAllFlips()">Contract All</a><p><small><strong>Chapters</strong></small></p>
<ul class="flipMenu" imagepath="../js/flipmenu">
<li id="no" title="Introduction" expanded="false">Introduction<ul>
<li><a href="introduction.html">
              Top of chapter
            </a></li>
<li title="Purpose"><a href="introduction.html#id60800">Purpose</a></li>
<li title="Prerequisites"><a href="introduction.html#id60757">Prerequisites</a></li>
</ul>
</li>
<li id="no" title="Overview" expanded="false">Overview<ul>
<li><a href="overview.html">
              Top of chapter
            </a></li>
<li title="Built-In Mechanisms"><a href="overview.html#id62194">Built-In Mechanisms</a></li>
<li title="C and Java Libraries"><a href="overview.html#id60915">C and Java Libraries</a></li>
<li title="Standard Protocols"><a href="overview.html#id62774">Standard Protocols</a></li>
<li title="IC"><a href="overview.html#id61047">IC</a></li>
<li title="Old Applications"><a href="overview.html#id62555">Old Applications</a></li>
</ul>
</li>
<li id="no" title="Problem Example" expanded="false">Problem Example<ul>
<li><a href="example.html">
              Top of chapter
            </a></li>
<li title="Description"><a href="example.html#id63860">Description</a></li>
</ul>
</li>
<li id="loadscrollpos" title="Ports" expanded="true">Ports<ul>
<li><a href="c_port.html">
              Top of chapter
            </a></li>
<li title="Erlang Program"><a href="c_port.html#id58262">Erlang Program</a></li>
<li title="C Program"><a href="c_port.html#id62416">C Program</a></li>
<li title="Running the Example"><a href="c_port.html#id63496">Running the Example</a></li>
</ul>
</li>
<li id="no" title="Erl_Interface" expanded="false">Erl_Interface<ul>
<li><a href="erl_interface.html">
              Top of chapter
            </a></li>
<li title="Erlang Program"><a href="erl_interface.html#id63174">Erlang Program</a></li>
<li title="C Program"><a href="erl_interface.html#id63282">C Program</a></li>
<li title="Running the Example"><a href="erl_interface.html#id61784">Running the Example</a></li>
</ul>
</li>
<li id="no" title="Port drivers" expanded="false">Port drivers<ul>
<li><a href="c_portdriver.html">
              Top of chapter
            </a></li>
<li title="Port Drivers"><a href="c_portdriver.html#id61981">Port Drivers</a></li>
<li title="Erlang Program"><a href="c_portdriver.html#id62001">Erlang Program</a></li>
<li title="C Driver"><a href="c_portdriver.html#id62119">C Driver</a></li>
<li title="Running the Example"><a href="c_portdriver.html#id63970">Running the Example</a></li>
</ul>
</li>
<li id="no" title="C Nodes" expanded="false">C Nodes<ul>
<li><a href="cnode.html">
              Top of chapter
            </a></li>
<li title="Erlang Program"><a href="cnode.html#id64088">Erlang Program</a></li>
<li title="C Program"><a href="cnode.html#id64168">C Program</a></li>
<li title="Running the Example"><a href="cnode.html#id64499">Running the Example</a></li>
</ul>
</li>
<li id="no" title="NIFs" expanded="false">NIFs<ul>
<li><a href="nif.html">
              Top of chapter
            </a></li>
<li title="NIFs"><a href="nif.html#id64799">NIFs</a></li>
<li title="Erlang Program"><a href="nif.html#id64820">Erlang Program</a></li>
<li title="NIF library code"><a href="nif.html#id64884">NIF library code</a></li>
<li title="Running the Example"><a href="nif.html#id64985">Running the Example</a></li>
</ul>
</li>
</ul>
</div></div>
<div id="content">
<div class="innertube">
<h1>4 Ports</h1>
  
  <p>This is an example of how to solve the <span class="bold_code"><a href="example.html">example problem</a></span> by using a port.</p>
  <img alt="IMAGE MISSING" src="../tutorial/port.gif"><br>
    <em>Figure
        4.1:
         
        Port Communication.</em>
  

  <h3><a name="id58262">4.1 
        Erlang Program</a></h3>
    
    <p>First of all communication between Erlang and C must be established by creating the port. The Erlang process which creates a port is said to be <strong>the connected process</strong> of the port. All communication to and from the port should go via the connected process. If the connected process terminates, so will the port (and the external program, if it is written correctly).</p>
    <p>The port is created using the BIF <span class="code">open_port/2</span> with <span class="code">{spawn,ExtPrg}</span> as the first argument. The string <span class="code">ExtPrg</span> is the name of the external program, including any command line arguments. The second argument is a list of options, in this case only <span class="code">{packet,2}</span>. This option says that a two byte length indicator will be used to simplify the communication between C and Erlang. Adding the length indicator will be done automatically by the Erlang port, but must be done explicitly in the external C program.</p>
    <p>The process is also set to trap exits which makes it possible to detect if the external program fails.</p>
    <div class="example"><pre>
-module(complex1).
-export([start/1, init/1]).

start(ExtPrg) -&gt;
  spawn(?MODULE, init, [ExtPrg]).

init(ExtPrg) -&gt;
  register(complex, self()),
  process_flag(trap_exit, true),
  Port = open_port({spawn, ExtPrg}, [{packet, 2}]),
  loop(Port).</pre></div>
    <p>Now it is possible to implement <span class="code">complex1:foo/1</span> and <span class="code">complex1:bar/1</span>. They both send a message to the <span class="code">complex</span> process and receive the reply.</p>
    <div class="example"><pre>
foo(X) -&gt;
  call_port({foo, X}).
bar(Y) -&gt;
  call_port({bar, Y}).

call_port(Msg) -&gt;
  complex ! {call, self(), Msg},
  receive
    {complex, Result} -&gt;
      Result
  end.</pre></div>
    <p>The <span class="code">complex</span> process encodes the message into a sequence of bytes, sends it to the port, waits for a reply, decodes the reply and sends it back to the caller.</p>
    <div class="example"><pre>
loop(Port) -&gt;
  receive
    {call, Caller, Msg} -&gt;
      Port ! {self(), {command, encode(Msg)}},
      receive
    {Port, {data, Data}} -&gt;
          Caller ! {complex, decode(Data)}
      end,
      loop(Port)
 end.</pre></div>
    <p>Assuming that both the arguments and the results from the C functions will be less than 256, a very simple encoding/decoding scheme is employed where <span class="code">foo</span> is represented by the byte 1, <span class="code">bar</span> is represented by 2, and the argument/result is represented by a single byte as well.</p>
    <div class="example"><pre>
encode({foo, X}) -&gt; [1, X];
encode({bar, Y}) -&gt; [2, Y].
      
decode([Int]) -&gt; Int.</pre></div>
    <p>The resulting Erlang program, including functionality for stopping the port and detecting port failures is shown below.
      </p>
<div class="example"><pre>

-module(complex1).
-export([start/1, stop/0, init/1]).
-export([foo/1, bar/1]).

start(ExtPrg) -&gt;
    spawn(?MODULE, init, [ExtPrg]).
stop() -&gt;
    complex ! stop.

foo(X) -&gt;
    call_port({foo, X}).
bar(Y) -&gt;
    call_port({bar, Y}).

call_port(Msg) -&gt;
    complex ! {call, self(), Msg},
    receive
	{complex, Result} -&gt;
	    Result
    end.

init(ExtPrg) -&gt;
    register(complex, self()),
    process_flag(trap_exit, true),
    Port = open_port({spawn, ExtPrg}, [{packet, 2}]),
    loop(Port).

loop(Port) -&gt;
    receive
	{call, Caller, Msg} -&gt;
	    Port ! {self(), {command, encode(Msg)}},
	    receive
		{Port, {data, Data}} -&gt;
		    Caller ! {complex, decode(Data)}
	    end,
	    loop(Port);
	stop -&gt;
	    Port ! {self(), close},
	    receive
		{Port, closed} -&gt;
		    exit(normal)
	    end;
	{'EXIT', Port, Reason} -&gt;
	    exit(port_terminated)
    end.

encode({foo, X}) -&gt; [1, X];
encode({bar, Y}) -&gt; [2, Y].

decode([Int]) -&gt; Int.
</pre></div>  

  <h3><a name="id62416">4.2 
        C Program</a></h3>
    
    <p>On the C side, it is necessary to write functions for receiving and sending 
      data with two byte length indicators from/to Erlang. By default, the C program
      should read from standard input (file descriptor 0) and write to standard output
      (file descriptor 1). Examples of such functions, <span class="code">read_cmd/1</span> and
      <span class="code">write_cmd/2</span>, are shown below.</p>
<div class="example"><pre>

/* erl_comm.c */

typedef unsigned char byte;

read_cmd(byte *buf)
{
  int len;

  if (read_exact(buf, 2) != 2)
    return(-1);
  len = (buf[0] &lt;&lt; 8) | buf[1];
  return read_exact(buf, len);
}

write_cmd(byte *buf, int len)
{
  byte li;

  li = (len &gt;&gt; 8) &amp; 0xff;
  write_exact(&amp;li, 1);
  
  li = len &amp; 0xff;
  write_exact(&amp;li, 1);

  return write_exact(buf, len);
}

read_exact(byte *buf, int len)
{
  int i, got=0;

  do {
    if ((i = read(0, buf+got, len-got)) &lt;= 0)
      return(i);
    got += i;
  } while (got&lt;len);

  return(len);
}

write_exact(byte *buf, int len)
{
  int i, wrote = 0;

  do {
    if ((i = write(1, buf+wrote, len-wrote)) &lt;= 0)
      return (i);
    wrote += i;
  } while (wrote&lt;len);

  return (len);
}
</pre></div>    <p>Note that <span class="code">stdin</span> and <span class="code">stdout</span> are for buffered input/output and should not be used for the communication with Erlang!</p>
    <p>In the <span class="code">main</span> function, the C program should listen for a message from Erlang and, according to the selected encoding/decoding scheme, use the first byte to determine which function to call and the second byte as argument to the function. The result of calling the function should then be sent back to Erlang.</p>
<div class="example"><pre>

/* port.c */

typedef unsigned char byte;

int main() {
  int fn, arg, res;
  byte buf[100];

  while (read_cmd(buf) &gt; 0) {
    fn = buf[0];
    arg = buf[1];
    
    if (fn == 1) {
      res = foo(arg);
    } else if (fn == 2) {
      res = bar(arg);
    }

    buf[0] = res;
    write_cmd(buf, 1);
  }
}
      
</pre></div>    <p>Note that the C program is in a <span class="code">while</span>-loop checking for the return value of <span class="code">read_cmd/1</span>. The reason for this is that the C program must detect when the port gets closed and terminate.</p>
  

  <h3><a name="id63496">4.3 
        Running the Example</a></h3>
    
    <p>1. Compile the C code.</p>
    <div class="example"><pre>
unix&gt; <span class="bold_code">gcc -o extprg complex.c erl_comm.c port.c</span></pre></div>
    <p>2. Start Erlang and compile the Erlang code.</p>
    <div class="example"><pre>
unix&gt; <span class="bold_code">erl</span>
Erlang (BEAM) emulator version 4.9.1.2

Eshell V4.9.1.2 (abort with ^G)
1&gt; <span class="bold_code">c(complex1).</span>
{ok,complex1}</pre></div>
    <p>3. Run the example.</p>
    <div class="example"><pre>
2&gt; <span class="bold_code">complex1:start("extprg").</span>
&lt;0.34.0&gt;
3&gt; <span class="bold_code">complex1:foo(3).</span>
4
4&gt; <span class="bold_code">complex1:bar(5).</span>
10
5&gt; <span class="bold_code">complex1:stop().</span>
stop</pre></div>
  
</div>
<div class="footer">
<hr>
<p>Copyright © 2000-2012 Ericsson AB. All Rights Reserved.</p>
</div>
</div>
</div></body>
</html>