یکی از روشهای ارتباط ارلنگ با برنامههای دیگر یا در حقیقت استفاده از کدهای سایر زبانهای برنامه نویسی، استفاده از پورت است. البته پورت در ارلنگ مفهوم منحصر بفرد خاص خودش را دارد. پورت در ارلنگ خیلی شبیه پروسس است به این مفهوم که میتوان به آن پیام فرستاد و از آن پیام نیز دریافت کرد. برای فراخوانی تابعی در کد یک زبان دیگر،مثلا C ، نیاز است که ابتدا پورتی تعریف شود و در سمت برنامه C نیز مقداری کد نوشت تا بتوان با ارلنگ ارتباط برقرار کرد. لازم است جریان داده ارسالی از سمت ارلنگ در سمت کد C تعریف شده باشد تا بتواند جواب مربوط را بدهد. برای مثال فرض کنید میخواهیم از کد زیر استفاده کنیم. کد دارای دو تابع است و ما میخواهیم جمع ساده و ضرب را در ارلنگ با فراخوانی تابع زیر انجام دهیم:
int sum(int x, int y){ return x+y; } int twice(int x){ return 2*x; }
ما نیاز به دو کد C دیگر نیز داریم. یک کد driver که کارش مدیریت جریان داده و پیاده سازی پروتوکل ارتباطی به ارلنگ است و در آخر هم توابع مورد نظر را صدا میزند. یک کد ارتباطی دیگر برای خواندن از حافظه و نوشتن به آن. دو کد به ترتیب در پایین آورده شده است:
Driver:
#include <stdio.h> #include <stdlib.h> typedef unsigned char byte; int read_cmd(byte *buff); int write_cmd(byte *buff, int len); int sum(int x, int y); int twice(int x); int main() { int fn, arg1, arg2, result; byte buff[100]; while (read_cmd(buff) > 0) { fn = buff[0]; if (fn == 1) { arg1 = buff[1]; arg2 = buff[2]; /* debug -- you can print to stderr to debug * fprintf(stderr,"calling sum %i %i\n",arg1,arg2); */ result = sum(arg1, arg2); } else if (fn == 2) { arg1 = buff[1]; result = twice(arg1); } else { /* just exit on unknown function */ exit(EXIT_FAILURE); } buff[0] = result; write_cmd(buff, 1); } }
Comm:
#include <unistd.h> typedef unsigned char byte; #define HLEN 2 int read_cmd(byte *buf); int write_cmd(byte *buf, int len); int read_exact(byte *buf, int len); int write_exact(byte *buf, int len); int read_cmd(byte *buf) { int len; if (read_exact(buf, HLEN) != HLEN) return(-1); len = (buf[0] << 8) | buf[1]; return read_exact(buf, len); } int write_cmd(byte *buf, int len) { byte li; li = (len >> 8) & 0xff; write_exact(&li, 1); li = len & 0xff; write_exact(&li, 1); return write_exact(buf, len); } int read_exact(byte *buf, int len) { int i, got=0; do { if ((i = read(0, buf+got, len-got)) <= 0) return(i); got += i; } while (got<len); return(len); } int write_exact(byte *buf, int len) { int i, wrote = 0; do { if ((i = write(1, buf+wrote, len-wrote)) <= 0) return (i); wrote += i; } while (wrote<len); return (len); }
در آخر هم کد ارلنگ را نوشتم:
-module(calc). -export([start/0, stop/0]). -export([twice/1, sum/2]). start() -> register(calc, spawn(fun() -> process_flag(trap_exit, true), Port = open_port({spawn, "./calc"}, [{packet, 2}]), loop(Port) end)). stop() -> ?MODULE ! stop. twice(X) -> call_port({twice, X}). sum(X,Y) -> call_port({sum, X, Y}). call_port(Msg) -> ?MODULE ! {call, self(), Msg}, receive {?MODULE, Result} -> Result end. loop(Port) -> receive {call, Caller, Msg} -> Port ! {self(), {command, encode(Msg)}}, receive {Port, {data, Data}} -> Caller ! {?MODULE, decode(Data)} end, loop(Port); stop -> Port ! {self(), close}, receive {Port, closed} -> exit(normal) end; {'EXIT', Port, Reason} -> exit({port_terminated, Reason}) end. encode({sum, X, Y}) -> [1, X, Y]; encode({twice, X}) -> [2, X]. decode([Int]) -> Int.
ابتدا برنامه C را کامپایل میکنیم:
gcc -o calc calc.c calc_comm.c calc_driver.c
برنامه ارلنگ را کامپایل و اجرا میکنیم و پس از آن براحتی میتوانیم تابع sum را فراخوانی کنیم.