首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

Erlang 與 C 節點通訊實戰:erl_interface 構建 CNode 完整教學

     編輯:關於C

架構概覽

  • CNode:用 C 實現的 Erlang 节點,通過 erl_interface 庫與 Erlang VM 通訊。
  • 通訊協議:基於 TCP 的 Erlang Distribution Protocol。
  • 優勢:隔離崩潰風險(獨立進程),適合高效能/舊系統整合。

Windows 環境建置步驟

  1. 安裝 Erlang (例 R16B02),取得 include、lib 目錄:
    erl5.10.3\lib\erl_interface-3.7.14\include
    erl5.10.3\lib\erl_interface-3.7.14\lib (需 ei_md.lib、erl_interface_md.lib)
  2. VS 建立 C 專案,設定:
    Include 目錄加入 include
    Library 目錄加入 lib
    連結器輸入加入 ws2_32.lib ei_md.lib erl_interface_md.lib
    字元集設為 Unicode
  3. 編譯生成 cnode.exe

CNode Server 端核心代碼

#include 
#include 
#include "erl_interface.h"
#include "ei.h"

#define BUFSIZE 1000
#define PORT 8088

int foo(int x) { return x + 1; }
int bar(int y) { return y * 2; }

int main() {
    WSADATA wsa; WSAStartup(MAKEWORD(2,2), &wsa);
    erl_init(NULL, 0);

    struct in_addr addr; addr.s_addr = inet_addr("127.0.0.1");
    if (erl_connect_xinit("idril", "cnode", "cnode@127.0.0.1", &addr, "secretcookie", 0) == -1)
        erl_err_quit("erl_connect_xinit");

    int listen = my_listen(PORT);
    erl_publish(PORT);
    int fd = erl_accept(listen, &conn);
    fprintf(stderr, "Connected to %s\n", conn.nodename);

    while (1) {
        ErlMessage emsg; unsigned char buf[BUFSIZE];
        int got = erl_receive_msg(fd, buf, BUFSIZE, &emsg);
        if (got == ERL_TICK) continue;
        if (got == ERL_ERROR) break;

        if (emsg.type == ERL_REG_SEND) {
            ETERM *fromp = erl_element(2, emsg.msg);
            ETERM *tuplep = erl_element(3, emsg.msg);
            ETERM *fnp = erl_element(1, tuplep);
            ETERM *argp = erl_element(2, tuplep);
            int res = (strncmp(ERL_ATOM_PTR(fnp), "foo", 3) == 0) ? foo(ERL_INT_VALUE(argp))
                                                                   : bar(ERL_INT_VALUE(argp));
            ETERM *resp = erl_format("{cnode, ~i}", res);
            erl_send(fd, fromp, resp);
            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);
        }
    }
    return 0;
}

int my_listen(int port) {
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in addr = {0};
    addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = INADDR_ANY;
    bind(fd, (struct sockaddr*)&addr, sizeof(addr));
    listen(fd, 5); return fd;
}

Erlang 客戶端測試

% 啟動 Erlang 節點
erl -name e1@127.0.0.1 -setcookie secretcookie

% 連接 CNode
net_kernel:connect('cnode@127.0.0.1').  % -> true

% 發送異步訊息
{any, 'cnode@127.0.0.1'} ! {call, self(), {bar, 3}}.
flush().  % 收到 {cnode,6}

{any, 'cnode@127.0.0.1'} ! {call, self(), {foo, 3}}.
flush().  % 收到 {cnode,4}

常見問題排查

現象原因解決
連接失敗epmd 未啟動先啟動一個 Erlang 節點或執行 epmd.exe
編譯錯誤Erlang 版本不匹配嚴格使用構建時的 Erlang 版本 (例 R16B02)
Cookie 不合雙方 cookie 不同雙方統一 -setcookie secretcookie
節點名稱衝突名稱重複確保 cnode@127.0.0.1 唯一

CNode Client 端關鍵差異

erl_connect_init(1, "secretcookie", 0);
int fd = erl_connect("e1@idril");  // 主動連接已知節點
// 後續收發迴圈與 Server 相同

參考資源

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved