【原创】erlang 模块之 epmd

简介:

什么是 epmd ?


在《Erlang/OTP 并发编程实战》中,对 epmd 有如下描述:  
  • epmd  代表 Erlang 端口映射守护进程(Erlang Port Mapper Daemon)。
  • 每启动一个节点,都会检查本地机器上是否运行着 epmd ,如果没有,节点就会自行启动 epmd 。
  • epmd 会追踪在本地机器上运行的每个节点,并记录分配给它们的端口。
  • 当一台机器上的 Erlang 节点试图与某远程节点通信时,本地的 epmd 就会联络远程机器上的 epmd(默认使用 TCP/IP 端口 4369),询问在远程机器上有没有叫相应名字的节点。如果有,远程的 epmd 就会回复一个端口号,通过该端口便可直接与远程节点通信。
  • epmd 不会自动搜索其他 epmd ,只有在某个节点主动搜寻其他节点时通信才能建立。 
在《Learn You Some Erlang for Great Good!》中有如下描述:  
When you start a node, you give it a name, and it will connect to an application called Erlang Port Mapper Daemon (EPMD), which will run on each of the computers that are part of your Erlang cluster. EPMD will act as a name server that lets nodes register themselves, contact other nodes by name rather than port numbers, and warn you about any name clashes.
If you need to go through a firewall with distributed Erlang (and do not want to tunnel), you will likely want to open a few ports here and there for Erlang communication. In this case, you should open port 4369, the default port for EPMD. It’s a good idea to use this port, because it has been officially registered for EPMD by Ericsson. This means that any standards-compliant operating system you use will have that port free, ready for EPMD.

Erlang 中和 epmd 相关的文件


在 otp_src_xxx\erts\epmd\  中,实现了 epmd 服务程序和 epmd 命令行程序。  

【epmd.c】  
  • 函数 epmd_dbg 是对函数 epmd 的封装,便于在 debug 模式下使用 epmd ;
  • 给出了如何在 linux 和 windows 上实现 daemon 函数,以及与 syslog 的配合;
【epmd.h】  
定义了 epmd 所采用协议的消息编码(C语言侧定义)。  

【epmd_int.h】  
针对跨平台函数和变量进行定义。  

【epmd_cli.c】  
实现了 epmd 命令行功能所需的的 API 调用。  

【epmd_srv.c】  
  • 基于 select 实现了 epmd 服务程序的事件驱动主循环;实现了针对上述 epmd 协议的解析。服务模型为一问一答式。
  • 通过对 select 超时时间的约束(最大 5s),模拟了 busy server 的 delay_accept 和 delay_write 功能。

在 otp_src_xxx\lib\kernel\src\ 中,在 erlang 代码层面实现了与 epmd 服务程序的协议交互。  

【erl_epmd.erl】  
基于 gen_server 行为模式、采用 TCP socket 方式与本地或远端 epmd 进行协议通信的实现。  

【erl_epmd.hrl】  
定义了 epmd 所使用协议的消息编码(Erlang 语言侧定义)。  


在 otp_src_xxx\lib\erl_interface\src\epmd\ 中,与 erlang 层实现对应的底层 C 实现。  

【ei_epmd.h】  
常量定义。  

【epmd_port.c】  
通过 TCP socket 连接本地或远端 epmd ,并通过协议 EPMD_PORT2_REQ 获取 the distribution port of another node 。  

【epmd_publish.c】  
通过协议 EPMD_ALIVE2_REQ 向隐藏 node 发布自身的 listen port 和 alive name。  

【epmd_unpublish.c】  
通过协议 EPMD_STOP_REQ 停止指定名字的 node。  


EPMD Protocol


erts-5.9.2 中的内容  
1 
 
 
2 
 
3 
 
4 
 
5 
 
6 
 
7 
 
8 
 
9 
 


erts-7.1 中的内容  
10 
 
11 
 
12 
 
13 
 
14 
 
15 
 
16 
 
17 
 


实验分析


节点注册  
 

注册信息查询  
 


杀掉 epmd


整个实验抓包





实验操作步骤

初始状态,没有启动 epmd 和任何 erlang 程序

[root@Betty ~]# 
[root@Betty ~]# ps aux|grep epmd
root      6843  0.0  0.0 103252   852 pts/2    S+   14:45   0:00 grep epmd
[root@Betty ~]# 
[root@Betty ~]# ps aux|grep beam
root      6845  0.0  0.0 103252   848 pts/2    S+   14:45   0:00 grep beam
[root@Betty ~]#
在另一个窗口启动分布式 erlang 节点 a  
[root@Betty ~]# 
[root@Betty ~]# erl -sname a
Erlang/OTP 17 [erts-6.0] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V6.0  (abort with ^G)
(a@Betty)1>
重新查看,发现此时 epmd 已经随之启动  
[root@Betty ~]# 
[root@Betty ~]# ps aux|grep epmd
root      6855  0.0  0.0  10828   392 ?        S    14:45   0:00 /usr/local/lib/erlang/erts-6.0/bin/epmd -daemon
root      6878  0.0  0.0 103252   848 pts/2    S+   14:45   0:00 grep epmd
[root@Betty ~]# 
[root@Betty ~]# ps aux|grep beam
root      6849  0.6  0.4 744584 16652 pts/4    Sl+  14:45   0:00 /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -sname a
root      6880  0.0  0.0 103252   848 pts/2    S+   14:46   0:00 grep beam
[root@Betty ~]#
查看节点注册信息  
[root@Betty ~]# 
[root@Betty ~]# epmd -names
epmd: up and running on port 4369 with data:
name a at port 34919
[root@Betty ~]#
在 erlang shell 中查看本地注册信息  
(a@Betty)1> 
(a@Betty)1> erl_epmd:names().
{ok,[{"a",34919}]}
(a@Betty)2>
查看另一台主机 YOYO 上 epmd 的注册信息,此时会报错(因为 YOYO 主机上此时 epmd 尚未运行)  
(a@Betty)2> erl_epmd:names("YOYO").
{error,address}
(a@Betty)3>
主机 YOYO 尚未运行 epmd 时的状态  
[root@YOYO ~]# 
[root@YOYO ~]# ps aux|grep epmd
root      7620  0.0  0.0 103256   848 pts/2    S+   14:47   0:00 grep epmd
[root@YOYO ~]# 
[root@YOYO ~]# ps aux|grep beam
root      7622  0.0  0.0 103256   848 pts/2    S+   14:47   0:00 grep beam
[root@YOYO ~]#
启动分布式 erlang 节点 b  
[root@YOYO ~]# 
[root@YOYO ~]# erl -sname b    
Erlang/OTP 17 [erts-6.0] [source] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V6.0  (abort with ^G)
(b@YOYO)1>
此时状态变为  
[root@YOYO ~]# 
[root@YOYO ~]# ps aux|grep epmd
root      7629  0.0  0.0  10828   392 ?        S    14:47   0:00 /usr/local/lib/erlang/erts-6.0/bin/epmd -daemon
root      7650  0.0  0.0 103256   848 pts/2    S+   14:47   0:00 grep epmd
[root@YOYO ~]# 
[root@YOYO ~]# ps aux|grep beam
root      7623  3.0  0.4 589900 16720 pts/1    Sl+  14:47   0:00 /usr/local/lib/erlang/erts-6.0/bin/beam.smp -- -root /usr/local/lib/erlang -progname erl -- -home /root -- -sname b
root      7652  0.0  0.0 103256   844 pts/2    S+   14:47   0:00 grep beam
[root@YOYO ~]# 
[root@YOYO ~]# epmd -names
epmd: up and running on port 4369 with data:
name b at port 40969
[root@YOYO ~]#
在主机 Betty 的 erlang shell 中重新查询主机 YOYO 上 epmd 的注册信息,此时可以获得 b 的注册内容  
(a@Betty)3> 
(a@Betty)3> erl_epmd:names("YOYO").
{ok,[{"b",40969}]}
(a@Betty)4>
在主机 YOYO 上的 erlang shell 里反向查询 Betty 主机上 epmd 的注册信息  
(b@YOYO)1> 
(b@YOYO)1> erl_epmd:names().
{ok,[{"b",40969}]}
(b@YOYO)2> erl_epmd:names("Betty").
{ok,[{"a",34919}]}
(b@YOYO)3>
终止主机 Betty 上 erlang 节点 a 的运行  
(a@Betty)4> 
(a@Betty)4> 
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
       (v)ersion (k)ill (D)b-tables (d)istribution
^C[root@Betty ~]# 
[root@Betty ~]#
查看此时状态  
[root@Betty ~]# 
[root@Betty ~]# ps aux|grep beam
root      6890  0.0  0.0 103252   852 pts/2    S+   14:49   0:00 grep beam
[root@Betty ~]# 
[root@Betty ~]# ps aux|grep epmd
root      6855  0.0  0.0  10828   424 ?        S    14:45   0:00 /usr/local/lib/erlang/erts-6.0/bin/epmd -daemon
root      6893  0.0  0.0 103252   852 pts/2    S+   14:49   0:00 grep epmd
[root@Betty ~]# 
[root@Betty ~]# epmd -names
epmd: up and running on port 4369 with data:
[root@Betty ~]#
杀死 epmd  
[root@Betty ~]# epmd -kill
Killed
[root@Betty ~]# 
[root@Betty ~]# 
[root@Betty ~]# ps aux|grep epmd
root      6897  0.0  0.0 103252   852 pts/2    S+   14:49   0:00 grep epmd
[root@Betty ~]#


目录
相关文章
|
网络安全 数据安全/隐私保护
等保二级配置(四)口令复杂度策略和禁止root登录
等保二级配置(四)口令复杂度策略和禁止root登录
968 0
|
JSON NoSQL Redis
redis-full-check校验工具
redis-full-check是阿里云Redis&MongoDB团队开源的用于校验2个redis数据是否一致的工具,通常用于redis数据迁移后正确性的校验。
28110 0
|
2月前
|
人工智能 机器人 开发者
真香!机器人终于不只会回消息:3.3 万 Star AstrBot 把多平台、插件和 Agent 拧成一套开源底座
AstrBot 是一个开源的一体化 Agent 聊天机器人平台,把 QQ、企业微信、微信公众号、飞书、Telegram、Slack 等平台接入同一个 Agent 工作台。
641 1
|
索引
树莓派 Raspberry Pi (bullseye)更换阿里云源方法
树莓派 Raspberry Pi (bullseye)更换阿里云源方法
14552 2
|
移动开发 NoSQL Redis
阿里云Redis lua命令支持及相关限制说明
介绍阿里云Redis对lua命令的支持
13151 1
|
3月前
|
安全 API 数据安全/隐私保护
内网 DeepSeek Harness 远程安全访问完整教程
DeepSeek Harness是DeepSeek开源的智能体框架,支持插件化扩展,专注代码开发、仓库修改等任务。配合ZeroNews内网穿透,可安全将本地Web UI(http://127.0.0.1:3080)发布至公网,通过HTTPS域名+BasicAuth+IP/地域围栏多重防护,实现远程、可控、安全的Agent协作。
内网 DeepSeek Harness 远程安全访问完整教程
|
2月前
|
人工智能 JavaScript API
从0到1,DeepSeek Harness保姆级安装与实操完整教程
2026年8月AI领域迎来一波密集更新浪潮,多款大模型与智能体框架集中对外发布。DeepSeek不仅更新V4 Pro正式版本,补齐Agent工具调用、链式任务执行与软件工程相关能力,还正式开源DeepSeek Harness智能体运行框架。该项目凭借“一切皆插件”的创新设计理念,上线之后快速收获大量开发者关注,短短数天GitHub Star突破15万,成为平台历史上增长速度最快的开源项目之一,也标志着国内大模型行业的竞争逻辑,逐步从单纯比拼模型调用价格,转向底层架构、插件生态与智能体执行能力的综合比拼。
2508 2
|
8月前
|
人工智能 API 开发工具
【OpenClaw进阶保姆级教程】AI 编程效率翻倍!1分钟部署OpenClaw+集成Claude-Mem+Superpowers插件及避坑指南
AI编程助手的两大痛点始终困扰开发者:写代码时"转头就忘",跨会话重复踩坑;开发时缺乏工程思维,跳过设计、测试直接堆砌代码,最终产出一堆难以维护的"一次性代码"。2026年,Claude Code生态的两款神级插件——Claude-Mem(持久记忆插件)与Superpowers(工程化工作流插件),精准补上这两大短板,让AI编程助手从"好用"升级为"真正可靠的开发伙伴"。
3480 5
|
存储 关系型数据库 MySQL
手把手教教会你使用Wing FTP Server安装配置并结合内网穿透实现公网访问本地站点
手把手教教会你使用Wing FTP Server安装配置并结合内网穿透实现公网访问本地站点