如何通过 ID 获取 Erlang 端口?

How to get an Erlang port by its ID?

当我有一个 Erlang 进程 ID 时,使用 pid/3list_to_pid/1 函数(在内部做同样的事情)我可以获得用于调试目的的进程。

Process = pid(0,4,1).
Process = list_to_pid("<0.4.1>").

所以问题是; ports 呢?

有很多函数接口同时接受 process()port() 数据类型,例如 register/2。所以我需要知道是否有办法像进程一样通过 ID(例如 #Port<0.567>)获取端口。是禁止的吗?如果是这样,有什么原因吗?

我不知道标准库中有什么可以帮助解决这个问题,但是 the recon_lib:term_to_port/1 function in the recon library 可以满足您的需求。例如:

1> {ok,L} = gen_tcp:listen(0, []).
{ok,#Port<0.687>}
2> L = recon_lib:term_to_port("#Port<0.687>").
#Port<0.687>

此代码在临时端口上打开一个侦听套接字并将其存储在变量 L 中。然后它使用模式匹配断言,将字符串化端口 #Port<0.687> 传递给 recon_lib:term_to_port/1 returns 的结果与 L.

完全相同

首先,让我们尽早确定这一点,您需要了解为什么您认为需要此功能。也许你有一个很好的理由——但这对我来说很像一个 X-Y 问题。

[编辑:我刚刚看到史蒂夫的 post 为此使用了侦察库。如果您碰巧正在使用侦察,那将是一种很棒的方法。如果没有...去学习侦察。这是极好的。如果您是从头开始,下面的解决方案是。]

也就是说,让我们看看我们能做些什么,因为我们只有 erlang:port_to_list/1 可以使用(据我所知)。

考虑如下:

-module(porter).
-export([port/2]).

-spec port(non_neg_integer(), non_neg_integer()) -> undefined | port().
port(A, B) ->
    PortString = lists:flatten(io_lib:format("#Port<~w.~w>", [A, B])),
    CheckPort = fun(Z) -> PortString == erlang:port_to_list(Z) end,
    case lists:filter(CheckPort, erlang:ports()) of
        []  -> undefined;
        [P] -> P
    end.

并且在 shell:

1> c(porter).
{ok,porter}
2> erlang:ports().
[#Port<0.0>,#Port<0.318>,#Port<0.328>,#Port<0.337>]
3> porter:port(0, 328).
#Port<0.328>
4> porter:port(0, 400).
undefined

这可能符合您的目的,也可能不符合您的目的...但是,请再次考虑您为什么需要它。在您的项目中添加一个实用程序功能可能会更加明智,如果您需要手动操作它们,它会跟踪您实际打开的端口。