檢視原始碼 ei_connect

與分散式 Erlang 通訊。

說明

此模組使 C 程式能夠使用 TCP/IP 上的 Erlang 分散式功能與 Erlang 節點通訊。

C 節點對 Erlang 而言會顯示為隱藏節點。也就是說,知道 C 節點名稱的 Erlang 處理程序可以正常方式與其通訊,但節點名稱不會顯示在 erlang:nodes/0ERTS 中提供的清單中。

環境變數 ERL_EPMD_PORT 可用於指示 C 節點所屬的邏輯叢集。

逾時函式

大多數函式都以附加 _tmo 後綴的版本出現。這些函式會接收一個額外的引數,即以毫秒為單位的逾時時間。語義如下:對於操作中涉及的每個通訊基本元素,如果基本元素未在指定的時間內完成,則函式會傳回錯誤,且 erl_errno 會設定為 ETIMEDOUT。通訊基本元素是指在 socket 上的操作,例如 connectacceptrecvsend

顯然,逾時是用於實作容錯,而不是維持硬式即時承諾。_tmo 函式是用於偵測無回應的對等方,以及避免在 socket 操作上發生阻擋。

逾時值 0(零)表示已停用逾時。因此,使用最後一個引數為 0 呼叫 _tmo 函式,與不使用 _tmo 後綴呼叫函式相同。

如同所有其他以 ei_ 開頭的函式,您需要在程式中自行將 socket 設定為非阻擋模式。所有非阻擋模式的使用都內嵌在逾時函式內。在操作完成後,socket 一律會回到阻擋模式(無論結果為何)。為了避免問題,請不要變更 socket 選項。ei 會處理任何需要修改的 socket 選項。

在所有其他方面,_tmo 函式會繼承不含 _tmo 後綴的函式的所有傳回值和語義。

使用者提供的 Socket 實作

依預設,ei 會提供一個 TCP/IPv4 socket 介面,用於通訊。但是,使用者可以插入他/她自己的 IPv4 socket 實作。例如,以便透過 TLS 進行通訊。使用者提供的 socket 實作是透過將回呼結構傳遞至 ei_connect_init_ussi()ei_connect_xinit_ussi() 來插入的。

ei_socket_callbacks 結構中的所有回呼在成功時傳回零;失敗時傳回 posix 錯誤碼。

listenacceptconnect 回呼的 addr 引數是指目前使用通訊協定的適當位址結構。目前 ei 僅支援 IPv4。也就是說,目前 addr 一律指向 struct sockaddr_in 結構。

ei_socket_callbacks 結構未來可能會擴大。所有未設定的欄位,需要歸零。目前存在下列欄位

  • flags - 告知 ei 回呼行為的旗標。旗標應以位元方式 OR 運算在一起。如果未設定任何旗標,flags 欄位應包含 0。目前,支援的旗標

    • EI_SCLBK_FLG_FULL_IMPL - 如果設定,accept()connect()writev()write()read() 回呼會實作逾時。逾時會在 tmo 引數中傳遞,且以毫秒為單位。請注意,這些回呼的 tmo 引數與 ei API 中的逾時引數不同。零表示零逾時。也就是說,除非操作成功,否則會立即輪詢並逾時。EI_SCLBK_INF_TMO(最大 unsigned)表示無限逾時。當呼叫回呼時,檔案描述子處於阻擋模式,且當回呼傳回時,檔案描述子必須處於阻擋模式。

      如果未設定,ei 會使用 select() 來實作逾時,以便判斷何時呼叫回呼以及何時逾時。accept()connect()writev()write()read() 回呼的 tmo 引數應忽略。回呼可能會在非阻擋模式下呼叫。不允許回呼在阻擋和非阻擋模式之間變更。為了使此功能正常運作,select() 需要以與其與一般 socket 基本元素互動的方式相同的方式與所使用的 socket 基本元素互動。如果情況並非如此,回呼需要實作逾時,且應設定此旗標。

    未來可能會引入更多旗標。

  • int (*socket)(void **ctx, void *setup_ctx) - 建立 socket 和 socket 的內容。

    成功時,應將 *ctx 設定為指向已建立 socket 的內容。此內容將傳遞至所有其他 socket 回呼。此函式將傳遞與先前 ei_connect_init_ussi()ei_connect_xinit_ussi() 呼叫相同的 setup_context

    注意

    在 socket 的生命週期中,指標 *ctx 必須保持相同。也就是說,稍後不能重新定位。

    此回呼為必要項目。

  • int (*close)(void *ctx) - 關閉由 ctx 識別的 socket 並銷毀內容。

    此回呼為必要項目。

  • int (*listen)(void *ctx, void *addr, int *len, int backlog) - 將由 ctx 識別的 socket 繫結至本機介面,然後接聽。

    addrlen 引數既是輸入引數也是輸出引數。當呼叫時,addr 指向長度為 *len 的位址結構,其中包含如何繫結 socket 的資訊。傳回時,此回呼應已使用有關 socket 實際繫結方式的資訊來更新由 addr 所參考的結構。*len 應更新以反映 *addr 更新的大小。backlog 會識別接聽 socket 的待處理連線數大小。

    此回呼為必要項目。

  • int (*accept)(void **ctx, void *addr, int *len, unsigned tmo) - 接受由 *ctx 識別的接聽 socket 上的連線。

    當接受連線時,應建立已接受連線的新內容,且應更新 *ctx 以指向已接受連線的新內容。當呼叫時,addr 指向長度為 *len 的未初始化位址結構。傳回時,此回呼應已使用有關用戶端位址的資訊更新此結構。*len 應更新以反映 *addr 更新的大小。

    如果已設定 EI_SCLBK_FLG_FULL_IMPL 旗標,tmo 會包含以毫秒為單位的逾時時間。

    注意

    在 socket 的生命週期中,指標 *ctx 必須保持相同。也就是說,稍後不能重新定位。

    此回呼為必要項目。

  • int (*connect)(void *ctx, void *addr, int len, unsigned tmo) - 將由 ctx 識別的 socket 連線至由 addr 識別的位址。

    當呼叫時,addr 指向長度為 len 的位址結構,其中包含要連線位置的資訊。

    如果已設定 EI_SCLBK_FLG_FULL_IMPL 旗標,tmo 會包含以毫秒為單位的逾時時間。

    此回呼為必要項目。

  • int (*writev)(void *ctx, const void *iov, long iovcnt, ssize_t *len, unsigned tmo) - 在由 ctx 識別的已連線 socket 上寫入資料。

    iov 指向長度為 iovcntstruct iovec 結構陣列,其中包含要寫入 socket 的資料。成功時,此回呼應將 *len 設定為已成功寫入 socket 的位元組數。

    如果已設定 EI_SCLBK_FLG_FULL_IMPL 旗標,tmo 會包含以毫秒為單位的逾時時間。

    此回呼為選用項目。如果未實作,請將 ei_socket_callbacks 結構中的 writev 欄位設定為 NULL

  • int (*write)(void *ctx, const char *buf, ssize_t *len, unsigned tmo) - 在由 ctx 識別的已連線 socket 上寫入資料。

    當呼叫時,buf 指向長度為 *len 的緩衝區,其中包含要寫入 socket 的資料。成功時,此回呼應將 *len 設定為已成功寫入 socket 的位元組數。

    如果已設定 EI_SCLBK_FLG_FULL_IMPL 旗標,tmo 會包含以毫秒為單位的逾時時間。

    此回呼為必要項目。

  • int (*read)(void *ctx, char *buf, ssize_t *len, unsigned tmo) - 在由 ctx 識別的已連線 socket 上讀取資料。

    buf 指向長度為 *len 的緩衝區,其中應放置讀取的資料。成功時,此回呼應更新 *len 為已成功讀取 socket 的位元組數。

    如果已設定 EI_SCLBK_FLG_FULL_IMPL 旗標,tmo 會包含以毫秒為單位的逾時時間。

    此回呼為必要項目。

  • int (*handshake_packet_header_size)(void *ctx, int *sz) - 告知在 Erlang 分散式交握期間使用的交握封包標頭大小。

    成功時,*sz 應設定為要使用的交握封包標頭大小。有效值為 24。Erlang TCP 分散式使用 2 的交握封包大小,而 Erlang TLS 分散式使用 4 的交握封包大小。

    此回呼為必要項目。

  • int (*connect_handshake_complete)(void *ctx) - 當本機啟動的交握成功完成時呼叫。

    此回呼為選用項目。如果未實作,請將 ei_socket_callbacks 結構中的 connect_handshake_complete 欄位設定為 NULL

  • int (*accept_handshake_complete)(void *ctx) - 當遠端啟動的交握成功完成時呼叫。

    此回呼為選用項目。如果未實作,請將 ei_socket_callbacks 結構中的 accept_handshake_complete 欄位設定為 NULL

  • int (*get_fd)(void *ctx, int *fd) - 告知由 ctx 識別的 socket 所使用的檔案描述符。

    注意

    在 socket 的生命週期中,檔案描述符必須保持不變。也就是說,使用相同上下文 應該重複呼叫此回呼函數時,都必須回報相同的檔案描述符。

    檔案描述符必須是真實的檔案描述符。也就是說,在被 close() 回呼函數釋放之前,其他操作不應該能夠取得相同的檔案描述符。

    此回呼為必要項目。

資料型別

  • ei_cnode - 代表 C 節點的不透明資料型別。 ei_cnode 結構透過呼叫 ei_connect_init() 或其相關函數來初始化。

  • ei_socket_callbacks

    typedef struct {
        int flags;
        int (*socket)(void **ctx, void *setup_ctx);
        int   (*close)(void *ctx);
        int (*listen)(void *ctx, void *addr, int *len, int backlog);
        int (*accept)(void **ctx, void *addr, int *len, unsigned tmo);
        int (*connect)(void *ctx, void *addr, int len, unsigned tmo);
        int (*writev)(void *ctx, const void *iov, int iovcnt, ssize_t *len, unsigned tmo);
        int (*write)(void *ctx, const char *buf, ssize_t *len, unsigned tmo);
        int (*read)(void *ctx, char *buf, ssize_t *len, unsigned tmo);
        int (*handshake_packet_header_size)(void *ctx, int *sz);
        int (*connect_handshake_complete)(void *ctx);
        int (*accept_handshake_complete)(void *ctx);
        int (*get_fd)(void *ctx, int *fd);
    } ei_socket_callbacks;

    用於 使用者提供的 Socket 實作 的回呼函數。 每個欄位的文件可以在上面的使用者提供的 Socket 實作章節中找到。

  • ErlConnect

    typedef struct {
        char ipadr[4]; /* Ip v4 address in network byte order */
        char nodename[MAXNODELEN];
    } ErlConnect;

    IP v4 位址和節點名稱。

  • Erl_IpAddr

    typedef struct {
        unsigned s_addr; /* Ip v4 address in network byte order */
    } Erl_IpAddr;

    IP v4 位址。

  • erlang_msg

    typedef struct {
        long msgtype;
        erlang_pid from;
        erlang_pid to;
        char toname[MAXATOMLEN+1];
        char cookie[MAXATOMLEN+1];
        erlang_trace token;
    } erlang_msg;

    關於透過 ei_receive_msg() 或其相關函數接收到的訊息資訊。

ei_gethostbyaddr()

ei_gethostbyaddr_r()

ei_gethostbyname()

ei_gethostbyname_r()

struct hostent * ei_gethostbyaddr(const char *addr, int len, int type);
struct hostent * ei_gethostbyaddr_r(const char *addr, int length,  int type,
  struct hostent *hostp, char *buffer,   int buflen,  int *h_errnop);
struct hostent * ei_gethostbyname(const char *name);
struct hostent * ei_gethostbyname_r(const char *name,  struct hostent *hostp,
  char *buffer,  int buflen,  int *h_errnop);

一些常見名稱查詢函數的便利函數。

ei_accept()

int ei_accept(ei_cnode *ec, int listensock, ErlConnect *conp);

由伺服器程序用來接受來自客戶端程序的連線。

  • ec 是 C 節點結構。
  • listensock 是先前已呼叫 listen() 的開啟的 socket 描述符。
  • conp 是指向 ErlConnect 結構的指標。

成功時,conp 會填入連線客戶端的位址和節點名稱,並回傳一個檔案描述符。失敗時,會回傳 ERL_ERRORerl_errno 會設定為 EIO

ei_accept_tmo()

int ei_accept_tmo(ei_cnode *ec, int listensock, ErlConnect *conp, unsigned timeout_ms);

ei_accept 等效,帶有一個可選的超時參數,請參閱本手冊頁開頭的說明。

ei_close_connection()

int ei_close_connection(int fd);

關閉先前開啟的連線或監聽 socket。

自 OTP 21.3 起可用

ei_connect()

ei_xconnect()

ei_connect_host_port()

自 OTP 23.0 起可用

ei_xconnect_host_port()

int ei_connect(ei_cnode* ec, char *nodename);
int ei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename);
int ei_connect_host_port(ei_cnode* ec, char *hostname, int port);
int ei_xconnect_host_port(ei_cnode* ec, Erl_IpAddr adr, int port);

設定與 Erlang 節點的連線。

ei_xconnect() 需要指定遠端主機的 IP 位址和遠端節點的活動名稱。ei_connect() 提供替代介面,並從提供的節點名稱決定資訊。ei_xconnect_host_port() 函數提供另一種替代方案,即使遠端節點執行的主機上沒有 EPMD 實例也能運作。ei_xconnect_host_port() 函數需要指定遠端節點的 IP 位址和埠號。ei_connect_host_port() 函數是 ei_xconnect_host_port() 的替代方案,讓使用者可以指定主機名稱而不是 IP 位址。

  • adr 是遠端主機的 32 位元 IP 位址。
  • alive 是遠端節點的活動名稱。
  • node 是遠端節點的名稱。
  • port 是遠端節點的埠號。

這些函數成功時會回傳一個開啟的檔案描述符,或回傳一個負值表示發生錯誤。在後者的情況下,它們會將 erl_errno 設定為下列其中之一

  • EHOSTUNREACH - 無法連線到遠端主機 node

  • ENOMEM - 沒有更多可用記憶體。

  • EIO - I/O 錯誤。

此外,來自 socket(2)connect(2) 系統呼叫的 errno 值可能會傳播到 erl_errno 中。

範例

#define NODE   "madonna@chivas.du.etx.ericsson.se"
#define ALIVE  "madonna"
#define IP_ADDR "150.236.14.75"

/*** Variant 1 ***/
int fd = ei_connect(&ec, NODE);

/*** Variant 2 ***/
struct in_addr addr;
addr.s_addr = inet_addr(IP_ADDR);
fd = ei_xconnect(&ec, &addr, ALIVE);

自 OTP 23.0 起可用

ei_connect_init()

ei_connect_init_ussi()

自 OTP 21.3 起可用

ei_connect_xinit()

ei_connect_xinit_ussi()

int ei_connect_init(ei_cnode* ec, const char* this_node_name, const char *cookie, unsigned creation);
int ei_connect_init_ussi(ei_cnode* ec, const char* this_node_name, const char *cookie,
  unsigned creation, ei_socket_callbacks *cbs, int cbs_sz, void *setup_context);
int ei_connect_xinit(ei_cnode* ec, const char *thishostname, const char *thisalivename,
  const char *thisnodename, Erl_IpAddr thisipaddr, const char *cookie, unsigned creation);
int ei_connect_xinit_ussi(ei_cnode* ec, const char *thishostname, const char *thisalivename,
  const char *thisnodename, Erl_IpAddr thisipaddr, const char *cookie, unsigned creation,
  ei_socket_callbacks *cbs, int cbs_sz, void *setup_context);

初始化 ec 結構,以識別伺服器的節點名稱和 cookie。在其他作用於 ei_cnode 型別或與另一個節點連線的檔案描述符的函數被使用之前,必須先呼叫其中一個函數。

  • ec 是一個包含 C 節點相關資訊的結構。它在其他 ei 函數中用於連線和接收資料。

  • this_node_name 是 C 節點的名稱(完整節點名稱中 '@' 之前的名稱)。

  • cookie 是節點的 cookie。

  • creation 識別 C 節點的特定實例。它可以幫助防止節點接收傳送給先前具有相同註冊名稱的程序的訊息。

    注意

    在 OTP 25 中,creation 參數的型別從 short (16 位元) 變更為 unsigned int (32 位元)。除了可能出現編譯器警告外,這不應造成實際問題。

  • thishostname 是我們正在執行的機器的名稱。如果要使用長名稱,則必須是完整合格的名稱(也就是說,durin.erix.ericsson.se 而不是 durin)。

  • thisalivename 是本地 C 節點的名稱(完整節點名稱中 '@' 之前的名稱)。可以為 NULL (自 OTP 23 起),以從對等節點取得動態指定的名稱。

  • thisnodename 是本地 C 節點的完整名稱,也就是說,mynode@myhost。如果 thisalivenameNULL,則可以為 NULL

  • thispaddr 是主機的 IP 位址。

  • cbs 是指向實作替代 socket 介面的回呼結構的指標。

  • cbs_szcbs 指向的結構的大小。

  • setup_context 是指向一個結構的指標,該結構將作為第二個參數傳遞給 cbs 結構中的 socket 回呼。

充當伺服器的 C 節點在呼叫 ei_publish() 時會被指派一個建立編號。

連線只需關閉 socket 即可關閉。有關如何優雅地關閉 socket(在關閉之前有傳出的封包)的資訊,請參閱相關的系統文件。

這些函數會回傳一個負值表示發生錯誤。

範例 1

unsigned n = 0;
struct in_addr addr;
ei_cnode ec;
addr.s_addr = inet_addr("150.236.14.75");
if (ei_connect_xinit(&ec,
                     "chivas",
                     "madonna",
                     "madonna@chivas.du.etx.ericsson.se",
                     &addr;
                     "cookie...",
                     n++) < 0) {
    fprintf(stderr,"ERROR when initializing: %d",erl_errno);
    exit(-1);
}

範例 2

if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) {
    fprintf(stderr,"ERROR when initializing: %d",erl_errno);
    exit(-1);
}

自 OTP 21.3 起可用

ei_connect_tmo()

ei_xconnect_tmo()

ei_connect_host_port_tmo()

自 OTP 23.0 起可用

ei_xconnect_host_port_tmo()

int ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned timeout_ms);
int ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr adr, char *alivename, unsigned timeout_ms);
int ei_connect_host_port_tmo(ei_cnode* ec, char *hostname, int port, unsigned ms);
int ei_xconnect_host_port_tmo(ei_cnode* ec, Erl_IpAddr adr, int port, unsigned ms);

ei_connectei_xconnectei_connect_host_portei_xconnect_host_port 等效,帶有一個可選的超時參數,請參閱本手冊頁開頭的說明。

自 OTP 23.0 起可用

ei_get_tracelevel()

自 OTP R13B04 起可用

ei_set_tracelevel()

int ei_get_tracelevel(void);
void ei_set_tracelevel(int level);

用於設定分散式處理的追蹤。層級是不同的詳細程度層級。層級越高表示資訊越多。另請參閱除錯資訊章節。

這些函數不是執行緒安全的。

自 OTP R13B04 起可用

ei_listen()

自 OTP 21.3 起可用

ei_xlisten()

int ei_listen(ei_cnode *ec, int *port, int backlog);
int ei_xlisten(ei_cnode *ec, Erl_IpAddr adr, int *port, int backlog);

由伺服器程序用來設定監聽 socket,該 socket 稍後可用於接受來自客戶端程序的連線。

  • ec 是 C 節點結構。
  • adr 是要綁定的本地介面。
  • port 是指向包含要綁定埠號的整數的指標。如果在呼叫 ei_listen()*port 等於 0,則 socket 將綁定到臨時埠。成功時,ei_listen() 會將 *port 的值更新為實際綁定的埠。
  • backlog 是待處理連線的最大佇列。

ei_listen 將建立一個 socket,綁定到由 adr 識別的本地介面上的埠(如果呼叫 ei_listen() 則綁定到所有本地介面),並將該 socket 標記為被動 socket(也就是說,將用於接受傳入連線的 socket)。

成功時,會回傳一個檔案描述符,該描述符可以用於呼叫 ei_accept()。失敗時,會回傳 ERL_ERRORerl_errno 會設定為 EIO

自 OTP 21.3 起可用

ei_make_pid()

int ei_make_pid(ei_cnode *ec, erlang_pid *pid);

在參數 pid 中建立新的程序識別符。此程序識別符指向由參數 ec 識別的 C 節點上的概念性程序。成功時返回 0。失敗時返回 ERL_ERROR 並設置 erl_errno

ec 識別的 C 節點必須已初始化,並且在調用 ei_make_pid() 之前必須已收到名稱。C 節點的初始化是透過調用 ei_connect_init() 或其相關函式完成的。如果名稱是從對等節點動態分配的,則 C 節點也必須已連線。

自 OTP 23.0 起可用

ei_make_ref()

int ei_make_ref(ei_cnode *ec, erlang_ref *ref);

在參數 ref 中建立新的參考。此參考源自於由參數 ec 識別的 C 節點。成功時返回 0。失敗時返回 ERL_ERROR 並設置 erl_errno

ec 識別的 C 節點必須已初始化,並且在調用 ei_make_ref() 之前必須已收到名稱。C 節點的初始化是透過調用 ei_connect_init() 或其相關函式完成的。如果名稱是從對等節點動態分配的,則 C 節點也必須已連線。

自 OTP 23.0 起可用

ei_publish()

int ei_publish(ei_cnode *ec, int port);

伺服器程序使用此函式向本地名稱伺服器 EPMD 註冊,從而允許其他程序透過使用已註冊的名稱來發送訊息。在調用這些函式中的任何一個之前,程序應已在一個打開的套接字上調用了 bind()listen()

  • ec 是 C 節點結構。
  • port 是要註冊的本地名稱,並且應與之前綁定到套接字的埠號相同。
  • addr 是本地主機的 32 位元 IP 位址。

要從 EPMD 取消註冊,只需關閉返回的描述符即可。請勿使用 ei_unpublish(),因為它已被棄用。

成功時,該函式返回一個將調用程序連接到 EPMD 的描述符。失敗時,返回 -1,並且 erl_errno 會被設置為 EIO

此外,來自 socket(2)connect(2) 系統呼叫的 errno 值可能會傳播到 erl_errno 中。

ei_publish_tmo()

int ei_publish_tmo(ei_cnode *ec, int port, unsigned timeout_ms);

等同於 ei_publish,但帶有一個可選的超時參數,請參閱本手冊頁開頭的說明。

ei_receive()

int ei_receive(int fd, unsigned char* bufp, int bufsize);

接收由 Erlang 外部格式的位元組序列組成的訊息。

  • fd 是 Erlang 連線的打開描述符。它是從先前的 ei_connectei_accept 獲取的。
  • bufp 是足夠大的緩衝區,可以容納預期的訊息。
  • bufsize 指示 bufp 的大小。

如果發生滴答,也就是說,連線另一端的 Erlang 節點已輪詢此節點以查看它是否仍然存活,則該函式會返回 ERL_TICK,並且不會將任何訊息放置在緩衝區中。此外,erl_errno 會被設置為 EAGAIN

成功時,訊息會放置在指定的緩衝區中,並且該函式返回實際讀取的位元組數。失敗時,該函式返回 ERL_ERROR,並將 erl_errno 設置為以下之一

  • EAGAIN - 臨時錯誤:請重試。

  • EMSGSIZE - 緩衝區太小。

  • EIO - I/O 錯誤。

ei_receive_encoded()

int ei_receive_encoded(int fd, char **mbufp, int *bufsz,  erlang_msg *msg, int *msglen);

此函式保留是為了與介面編譯器產生的程式碼以及遵循同一應用程式中範例的程式碼相容。

本質上,該函式執行與 ei_xreceive_msg 相同的操作,但是該函式不是使用 ei_x_buff,而是期望一個指向字元指標 (mbufp) 的指標,其中字元指標是指向由 malloc 分配的記憶體區域。參數 bufsz 應是指向包含記憶體區域確切大小 (以位元組為單位) 的整數的指標。該函式可能會重新分配記憶體區域,並且在這種情況下,它將把新的大小放在 *bufsz 中並更新 *mbufp

返回 ERL_TICKerlang_msg *msgmsgtype 欄位。訊息的長度放在 *msglen 中。發生錯誤時,將返回 < 0 的值。

為了提高可讀性,建議在可能的情況下改用 ei_xreceive_msg。但是,為了保持相容性,該函式將保留在介面中,並且不會在未事先通知的情況下在未來版本中刪除。

ei_receive_encoded_tmo()

int ei_receive_encoded_tmo(int fd, char **mbufp, int *bufsz,  erlang_msg *msg,
  int *msglen, unsigned timeout_ms);

等同於 ei_receive_encoded,但帶有一個可選的超時參數,請參閱本手冊頁開頭的說明。

ei_receive_msg()

ei_xreceive_msg()

int ei_receive_msg(int fd, erlang_msg* msg, ei_x_buff* x);
int ei_xreceive_msg(int fd, erlang_msg* msg, ei_x_buff* x);

將訊息接收到 x 中的緩衝區。 ei_xreceive_msg 允許 x 中的緩衝區增長,但是如果訊息大於 x 中預先分配的緩衝區,則 ei_receive_msg 將會失敗。

  • fd 是 Erlang 連線的打開描述符。
  • msg 是指向 erlang_msg 結構的指標,其中包含有關所接收訊息的資訊。
  • x 是從 ei_x_new 取得的緩衝區。

成功時,該函式返回 ERL_MSG,並且會初始化 msg 結構。

msgtype 識別訊息的類型,並且是下列其中一項

  • ERL_SEND - 表示發生了普通的發送操作。 msg->to 包含接收者的 pid (C 節點)。

  • ERL_REG_SEND - 發生了已註冊的發送操作。 msg->from 包含發送者的 pid。

  • ERL_LINKERL_UNLINK - msg->tomsg->from 包含連結或取消連結的發送者和接收者的 pid。

  • ERL_EXIT - 表示連結中斷。 msg->tomsg->from 包含已連結程序的 pid。

返回值與 ei_receive 的相同。

ei_receive_msg_tmo()

ei_xreceive_msg_tmo()

int ei_receive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned imeout_ms);
int ei_xreceive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned timeout_ms);

等同於 ei_receive_msgei_xreceive_msg,但帶有一個可選的超時參數,請參閱本手冊頁開頭的說明。

ei_receive_tmo()

int ei_receive_tmo(int fd, unsigned char* bufp, int bufsize, unsigned timeout_ms);

等同於 ei_receive,但帶有一個可選的超時參數,請參閱本手冊頁開頭的說明。

ei_reg_send()

int ei_reg_send(ei_cnode* ec, int fd, char* server_name, char* buf, int len);

將 Erlang 項發送到已註冊的程序。

  • fd 是 Erlang 連線的打開描述符。
  • server_name 是目標接收者的已註冊名稱。
  • buf 是包含二進位格式項的緩衝區。
  • len 是訊息的長度 (以位元組為單位)。

如果成功,則返回 0,否則返回 -1。在後一種情況下,它會將 erl_errno 設置為 EIO

範例

將原子 "ok" 發送到程序 "worker"

ei_x_buff x;
ei_x_new_with_version(&x);
ei_x_encode_atom(&x, "ok");
if (ei_reg_send(&ec, fd, x.buff, x.index) < 0)
    handle_error();

ei_reg_send_tmo()

int ei_reg_send_tmo(ei_cnode* ec, int fd, char* server_name, char* buf, int len,
  unsigned timeout_ms);

等同於 ei_reg_send,但帶有一個可選的超時參數,請參閱本手冊頁開頭的說明。

ei_rpc()

ei_rpc_to()

ei_xrpc_to()

自 OTP 24.0 起可用

ei_rpc_from()

int ei_rpc(ei_cnode *ec, int fd, char *mod, char *fun, const char *argbuf,
  int argbuflen, ei_x_buff *x);
int ei_rpc_to(ei_cnode *ec, int fd, char *mod, char *fun, const char *argbuf,
  int argbuflen);
int ei_xrpc_to(ei_cnode *ec, int fd, char *mod, char *fun, const char *argbuf,
  int argbuflen, int flags);
int ei_rpc_from(ei_cnode *ec, int fd, int timeout, erlang_msg *msg, ei_x_buff *x);

支援在遠端節點上呼叫 Erlang 函式。 ei_rpc_to() 向遠端節點發送 RPC 請求,而 ei_rpc_from() 接收此類呼叫的結果。 ei_rpc() 將這兩個函式的功能結合在一起,方法是發送 RPC 請求並等待結果。

ei_xrpc_to()flags 參數設置為 0 時,該函式等同於 ei_rpc_to()。當 ei_xrpc_to() 的 flags 參數設置為 EI_RPC_FETCH_STDOUT 時,會轉發 stdout (標準輸出) 資料。有關 EI_RPC_FETCH_STDOUT 旗標的詳細資訊,請參閱 flags 參數的文件。

另請參閱 Kernel 中的 rpc:call/4

  • ec 是先前透過呼叫 ei_connect_init()ei_connect_xinit() 初始化的 C 節點結構。

  • fd 是 Erlang 連線的打開描述符。

  • timeout 是等待結果的最長時間 (以毫秒為單位)。 指定 ERL_NO_TIMEOUT 可永遠等待。 ei_rpc() 會無限期地等待答案,也就是說,呼叫永遠不會超時。

  • mod 是包含要在遠端節點上運行的函式的模組名稱。

  • fun 是要運行的函式名稱。

  • argbuf 是指向具有編碼 Erlang 清單 (不帶版本魔術數字) 的緩衝區的指標,其中包含要傳遞給函式的參數。

  • argbuflen 是包含編碼 Erlang 清單的緩衝區的長度。

  • msgerlang_msg 類型的結構,其中包含有關所接收訊息的資訊。 有關 erlang_msg 格式的說明,請參閱 ei_receive_msg

  • x 指向接收結果的動態緩衝區。 對於 ei_rpc(),這是沒有版本魔術數字的結果。 對於 ei_rpc_from() 呼叫,結果由版本魔術數字和一個 2 元組組成。 2 元組可以是以下兩種形式之一

    • {rex,Reply} - 此響應值表示 RPC 已完成。 結果值是 Reply 項。 這是可以從透過呼叫 ei_rpc_to()ei_xrpc_to() (不帶 EI_RPC_FETCH_STDOUT 旗標) 觸發的 RPC 獲得的唯一響應類型。 如果 RPC 是透過呼叫 ei_xrpc_to() 並設置 EI_RPC_FETCH_STDOUT 旗標觸發的,則已接收到所有轉發的 stdout 資料。

    • {rex_stdout,StdOutUTF8Binary} - 只有當 RPC 呼叫是透過呼叫 ei_xrpc_to() 並設定 EI_RPC_FETCH_STDOUT 旗標時,才能取得此回應值。此回應值表示已收到轉發的 stdout 資料。stdout 資料儲存在二進位檔中,並以 UTF-8 編碼。可能需要多次呼叫 ei_rpc_from() 才能讀取所有 stdout 資料。stdout 資料的接收順序與寫入順序相同。當從 ei_rpc_from() 呼叫取得 {rex,Reply} 元組時,表示已接收到所有轉發的 stdout 資料。

  • flags - 旗標 EI_RPC_FETCH_STDOUT 目前是 ei_xrpc_to() 唯一支援的旗標。當設定 EI_RPC_FETCH_STDOUT 時,被呼叫的函式會在一個新的行程中執行,並使用一個會轉發所有 stdout 資料的群組領導者。這表示在被呼叫函式執行期間,由被呼叫函式及其子代行程寫入的 stdout 資料都將被轉發(前提是群組領導者沒有透過呼叫 erlang:group_leader/2 而被變更)。轉發的 stdout 資料需要透過一系列對 ei_rpc_from() 的呼叫來收集。有關如何使用 ei_rpc_from() 接收 stdout 資料,請參閱 x 參數的描述。有關群組領導者概念的詳細資訊,請參閱I/O 協定的文件。

    注意

    只有在與版本大於或等於 OTP-24 的節點互動時,旗標 EI_RPC_FETCH_STDOUT 才會運作。

ei_rpc() 成功時會返回結果中的位元組數,失敗時會返回 -1ei_rpc_from() 會返回位元組數,否則會返回 ERL_TICKERL_TIMEOUTERL_ERROR 之一。函式 ei_rpc_to()ei_xrpc_to() 成功時會返回 0,否則返回 -1。失敗時,所有四個函式都會將 erl_errno 設定為以下其中之一

  • EIO - I/O 錯誤。

  • ETIMEDOUT - 超時時間已過。

  • EAGAIN - 臨時錯誤:請重試。

範例

檢查 Erlang 行程是否還活著

int index = 0, is_alive;
ei_x_buff args, result;

ei_x_new(&result);
ei_x_new(&args);
ei_x_encode_list_header(&args, 1);
ei_x_encode_pid(&args, &check_pid);
ei_x_encode_empty_list(&args);

if (ei_rpc(&ec, fd, "erlang", "is_process_alive",
           args.buff, args.index, &result) < 0)
    handle_error();

if (ei_decode_version(result.buff, &index) < 0
    || ei_decode_bool(result.buff, &index, &is_alive) < 0)
    handle_error();

ei_self()

erlang_pid * ei_self(ei_cnode *ec);

擷取 C 節點的通用 pid。每個 C 節點都有一個(偽)pid,用於 ei_send_regei_rpc() 等函式中。它包含在 ec 結構中的一個欄位中。請修改此結構。

成功時,會傳回一個指向行程識別碼的指標。失敗時,會傳回 NULL,並設定 erl_errno

ec 識別的 C 節點必須已初始化,並且在呼叫 ei_self() 之前必須已接收到名稱。C 節點的初始化是透過呼叫 ei_connect_init() 或其相關函式來完成的。如果名稱是從對等節點動態指派的,則 C 節點也必須已連線。

ei_send()

int ei_send(int fd, erlang_pid* to, char* buf, int len);

向行程傳送 Erlang term。

  • fd 是 Erlang 連線的打開描述符。
  • to 是訊息的目標接收者的 pid。
  • buf 是包含二進位格式項的緩衝區。
  • len 是訊息的長度 (以位元組為單位)。

如果成功,則返回 0,否則返回 -1。在後一種情況下,它會將 erl_errno 設置為 EIO

ei_send_encoded()

int ei_send_encoded(int fd, erlang_pid* to, char* buf, int len);

其運作方式與 ei_send 完全相同,保留替代名稱是為了向後相容性。在未事先通知的情況下,不會移除此函式。

ei_send_encoded_tmo()

int ei_send_encoded_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms);

等同於 ei_send_encoded,但帶有一個可選的逾時引數,請參閱本手冊頁開頭的描述。

ei_send_reg_encoded()

int ei_send_reg_encoded(int fd, const erlang_pid *from, const char *to, const char *buf, int len);

此函式保留是為了與介面編譯器產生的程式碼以及遵循同一應用程式中範例的程式碼相容。

此函式的運作方式與 ei_reg_send 相同,只有一個例外。它不以 ei_cnode 作為第一個引數,而是以第二個引數,也就是 erlang_pid,作為傳送行程(在 Erlang 分散式協定中)的行程識別碼。

可以透過呼叫 ei_self(cnode_pointer)ei_cnode 結構中擷取適當的 erlang_pid

ei_send_reg_encoded_tmo()

int ei_send_reg_encoded_tmo(int fd, const erlang_pid *from, const char *to, const char *buf,
  int len, unsigned timeout_ms);

等同於 ei_send_reg_encoded,但帶有一個可選的逾時引數,請參閱本手冊頁開頭的描述。

ei_send_tmo()

int ei_send_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms);

等同於 ei_send,但帶有一個可選的逾時引數,請參閱本手冊頁開頭的描述。

ei_thisnodename()

ei_thishostname()

ei_thisalivename()

const char * ei_thisnodename(ei_cnode *ec);
const char * ei_thishostname(ei_cnode *ec);
const char * ei_thisalivename(ei_cnode *ec);

可以用來擷取有關 C 節點的資訊。這些值最初是使用 ei_connect_init()ei_connect_xinit() 設定的。

這些函式只是從 ec 結構中提取適當的欄位。直接讀取該欄位在很長一段時間內可能都是安全的,因此這些函式並非真的需要。

ei_unpublish()

int ei_unpublish(ei_cnode *ec);

行程可以呼叫此函式,以取消在本機主機上從 EPMD 註冊指定的節點。但是,通常不允許這樣做,除非 EPMD 使用 -relaxed_command_check 旗標啟動,而通常情況下並非如此。

要取消發佈的節點,應該關閉 ei_publish() 返回的描述符。

警告

此函式已過時,並將在未來的版本中移除。

ec 是要取消註冊的節點的節點結構。

如果節點已成功從 EPMD 取消註冊,則函式會返回 0。否則,會返回 -1,並且 erl_errno 會設定為 EIO

ei_unpublish_tmo()

int ei_unpublish_tmo(ei_cnode *ec, unsigned timeout_ms);

等同於 ei_unpublish,但帶有一個可選的逾時引數,請參閱本手冊頁開頭的描述。

偵錯資訊

如果連線嘗試失敗,則可以檢查以下內容

  • erl_errno.
  • 使用了正確的 Cookie
  • EPMD 是否正在執行
  • 另一端的遠端 Erlang 節點是否正在執行與 ei 函式庫相同版本的 Erlang
  • 環境變數 ERL_EPMD_PORT 設定是否正確

可以透過使用 ei_set_tracelevel 或設定環境變數 EI_TRACELEVEL 來設定追蹤層級,以追蹤連線嘗試。追蹤層級具有以下訊息

  • 1:詳細錯誤訊息
  • 2:以上訊息和詳細警告訊息
  • 3:以上訊息和連線處理進度報告
  • 4:以上訊息和通訊進度報告
  • 5:以上訊息和資料轉換進度報告