programming erlang ch12 - andstudy/forge GitHub Wiki
-
example1.c
int twice(int x) { return 2 * x; } int sum(int x, int y) { return x + y; } -
erlang์์ ์คํํ๋ ํํ
X1 = example1:twice(23). Y1 = example1:sum(45, 32).
-
์ผ๋ญ ๋ณํ ํ๋ก๊ทธ๋๋ฐ์์ ํ๋ก์ธ์ค๋ฅผ ์์ฑํ๊ณ ๋ฉ์์ง๋ฅผ ์ก์์ ํ๋ ๊ฒ๊ณผ ๋น์ทํ๊ฒ ๋์
-
C ํ๋ก๊ทธ๋จ์ ์ผ๋ญ ์์คํ ์ธ๋ถ์์ ์คํ๋๊ณ , ํฌํธ๋ฅผ ํตํด์๋ง ๋ฉ์์ง๋ฅผ ์ก์์
-
๊ฐ์ฅ ๊ถ์ฅํ๋ ๋ฐฉ๋ฒ
-
ํฌํธ์์ฑ
@spec open_port(PortName, [Opt]) -> Port -
ํฌํธ๋ฅผ ํตํด C ํ๋ก๊ทธ๋จ์ผ๋ก ๋ฉ์์ง ์ ์ก ๋ฐ ์์
Port ! {PidC, {command, Data}} Port ! {PidC, {connect, Pid1}} Port ! {PidC, close} receive {Port, {data, Data}} -> ...
-
example1.erl
... start() -> ... Port = open_port({spawn, "./example1"}, [{packet, 2}]), ... loop(Port) -> receive {call, Caller, Msg} -> Port ! {self(), {command, encode(Msg)}}, receive {Port, {data, Data}} -> Caller ! {example1, decode(Data)} end, loop(Port); stop -> Port ! {self(), close}, receive {Port, closed} -> exit(normal) end; {'EXIT', Port, Reason} -> exit({port_terminated,Reason}) end. encode({twice, X}) -> [1, X]; encode({sum, X, Y}) -> [2, X, Y]. decode([Int]) -> Int. -
Port = open_port({spawn, "./example1"}, [{packet, 2}])
- 2๋ฐ์ดํธ ํค๋ ์๋ ์ถ๊ฐ (1, 2, 4์ค ํ์ผ)
- twice(10) ์ผ ๊ฒฝ์ฐ, <<0, 2, 1, 10>>
-
{Port, {data, Data}}
- ๋ฐ์ดํฐ ์์
-
{Port, closed}
- ํฌํธ๊ฐ ๋ซํ์ ๊ฒฝ์ฐ ์์
-
{'EXIT', Port, Reason}
- ์๋ฌ๊ฐ ๋ฌ์ ๊ฒฝ์ฐ ์์
-
example_driver1.c
int main() { int fn, arg1, arg2, result; byte buff[100]; while (read_cmd(buff) > 0) { fn = buff[0]; if (fn == 1) { arg1 = buff[1]; result = twice(arg1); } else if (fn == 2) { arg1 = buff[1]; arg2 = buff[2]; result = sum(arg1, arg2); } buff[0] = result; write_cmd(buff, 1); } } -
erl_comm.c
int read_cmd(byte *buf) { int len; if (read_exact(buf, 2) != 2) 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); } -
read(0, buf+got, len-got)
- ํ์ค ์ ๋ ฅ์ ํตํด erlang์ผ๋ก๋ถํฐ ๋ฉ์์ง ์์
-
write(1, buf+wrote, len-wrote)
- ํ์ค ์ถ๋ ฅ์ ํตํด erlang์ผ๋ก ๋ฉ์์ง ์ก์
-
erlang๊ณผ์ ํจํท์ ๋ง์ถ๊ธฐ ์ํด write_cmd ์ 2๋ฐ์ดํธ ํค๋ ์๋์ผ๋ก ์ถ๊ฐ
1> example1:start().
<0.32.0>
2> example1:sum(43, 32).
77
3> example1:twice(10).
20
- ํฌํธ ํ๋ก๊ทธ๋จ๊ณผ ์ ํํ๊ฒ ๋๊ฐ์ ํ๋กํ ์ฝ์ ๋ฐ๋ฅธ๋ค
- ์ผ๋ญ ์์คํ "๋ด๋ถ" ์์ ์คํ๋๋ค๋ ์ ์ด ํฌํธ์์ ์ฐจ์ด์
- ํจ์จ์ฑ ์ธก๋ฉด์์ ์ข์ ์๋ ์์ง๋ง, ๋ฌธ์ ๊ฐ ์๊ธธ ๊ฒฝ์ฐ ์ผ๋ญ ์์คํ ์ ์ํฅ์ ๋ฏธ์น๋ ์ํ์ฑ
-
example1_lid.erl
... start() -> start("example1_drv"). start(SharedLib) -> case erl_ddll:load_driver(".", SharedLib) of ok -> ok; {error, already_loaded} -> ok; _ -> exit({error, could_not_load_driver}) end, spawn(fun() -> init(SharedLib) end). init(SharedLib) -> register(example1_lid, self()), Port = open_port({spawn, SharedLib}, []), loop(Port). ... -
erl_ddll:load_driver(".", SharedLib)
- C ๋๋ผ์ด๋ฒ๋ฅผ (Unix์์๋ so, Windows์์๋ dll) ์ผ๋ญ ์์คํ ๋ด๋ถ์ ๋ก๋ฉ
-
open_port({spawn, SharedLib}, [])
- ํฌํธ ์์ฑ
-
example1_lid.c
#include <stdio.h> #include "erl_driver.h" typedef struct { ErlDrvPort port; } example_data; static ErlDrvData example_drv_start(ErlDrvPort port, char *buff) { example_data* d = (example_data*)driver_alloc(sizeof(example_data)); d->port = port; return (ErlDrvData)d; } static void example_drv_stop(ErlDrvData handle) { driver_free((char*)handle); } static void example_drv_output(ErlDrvData handle, char *buff, int bufflen) { example_data* d = (example_data*)handle; char fn = buff[0], arg = buff[1], res; if (fn == 1) { res = twice(arg); } else if (fn == 2) { res = sum(buff[1], buff[2]); } driver_output(d->port, &res, 1); } ErlDrvEntry example_driver_entry = { NULL, /* F_PTR init, N/A */ example_drv_start, /* L_PTR start, called when port is opened */ example_drv_stop, /* F_PTR stop, called when port is closed */ example_drv_output, /* F_PTR output, called when erlang has sent data to the port */ NULL, /* F_PTR ready_input, called when input descriptor ready to read*/ NULL, /* F_PTR ready_output, called when output descriptor ready to write */ "example1_drv", /* char *driver_name, the argument to open_port */ NULL, /* F_PTR finish, called when unloaded */ NULL, /* F_PTR control, port_command callback */ NULL, /* F_PTR timeout, reserved */ NULL /* F_PTR outputv, reserved */ }; DRIVER_INIT(example_drv) /* must match name in driver_entry */ { return &example_driver_entry; }
}}}
- driver_alloc
- thread-safe, driver_free๋ฅผ ํตํด ๋ช ์์ ์ผ๋ก ํด์ ํด์ผ ํจ
- driver_free
- thread-safe, driver_alloc์ ํตํด ์์ฑํ ๋ฉ๋ชจ๋ฆฌ ํด์
- driver_output
- Port Owner๋ก ๋ฉ์์ง ์ก์
1> c(example1_lid).
{ok, example1_lid}
2> example1_lid:start().
<0.41.0>
3> example1_lid:twice(50).
100
4> example1_lid:sum(10, 20).
30
- ๋ถ์ฐ ํ๋ก๊ทธ๋๋ฐ๊ณผ ์ ์ฌํ๊ฒ ์คํ
- ์ผ๋ญ ํ๋ก๊ทธ๋จ ๊ด์ ์์ C ํ๋ก๊ทธ๋จ์ด ํ๋์ ๋ ธ๋์ฒ๋ผ ํ๋
- erl_interface๋ฅผ ํตํด C ํ๋ก๊ทธ๋จ ์์ฑ
- ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ ๋งค์ฐ ๋๋ฌผ๋ค (๋๋ถ๋ถ ํฌํธ๋ก ์ถฉ๋ถ)
-
example1_cnode.erl
-module(example1_cnode). -export([twice/1, sum/2]). twice(X) -> X * 2. sum(X, Y) -> X + Y.
-
example1_cnode.c
#define __WIN32__ #include "C:\Program Files\erl5.6.3\lib\erl_interface-3.5.7\include\erl_interface.h" #include "C:\Program Files\erl5.6.3\lib\erl_interface-3.5.7\include\ei.h" int main(int argc, char **argv) { int fd; /* fd to Erlang node */ int res; ETERM *rpcp, *resp, *argp; erl_init(NULL, 0); if (erl_connect_init(1, "secretcookie", 0) == -1) erl_err_quit("erl_connect_init"); if ((fd = erl_connect("erlang_node@SSB-PC")) < 0) erl_err_quit("erl_connect"); fprintf(stderr, "Connected to erlang_node@SSB-PC\n\r"); /* twice(10) */ argp = erl_format("[~i]", 10); rpcp = erl_rpc(fd, "example1_cnode", "twice", argp); res = ERL_INT_VALUE(rpcp); fprintf(stderr, "rpc:call(erlang_node@SSB-PC, example1_cnode, twice, [10])\r\n%d\r\n", res); erl_free_term(argp); erl_free_term(rpcp); /* sum(11, 22) */ argp = erl_format("[~i, ~i]", 11, 22); rpcp = erl_rpc(fd, "example1_cnode", "sum", argp); res = ERL_INT_VALUE(rpcp); fprintf(stderr, "rpc:call(erlang_node@SSB-PC, example1_cnode, sum, [11, 22])\r\n%d\r\n", res); erl_free_term(argp); erl_free_term(rpcp); }
d:\>erl -sname erlang_node -setcookie secretcookie
d:\>example1_cnode.exe
Connected to erlang_node@SSB-PC
rpc:call(erlang_node@SSB-PC, example1_cnode, twice, [10])
20
rpc:call(erlang_node@SSB-PC, example1_cnode, sum, [11, 22])
33