如何通过 ID 获取 Erlang 端口?
How to get an Erlang port by its ID?
当我有一个 Erlang 进程 ID 时,使用 pid/3
或 list_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
这可能符合您的目的,也可能不符合您的目的...但是,请再次考虑您为什么需要它。在您的项目中添加一个实用程序功能可能会更加明智,如果您需要手动操作它们,它会跟踪您实际打开的端口。
当我有一个 Erlang 进程 ID 时,使用 pid/3
或 list_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
这可能符合您的目的,也可能不符合您的目的...但是,请再次考虑您为什么需要它。在您的项目中添加一个实用程序功能可能会更加明智,如果您需要手动操作它们,它会跟踪您实际打开的端口。