Erlang-код для получения списка всех IP-адресов


Это какой-то Эрланг код, который я написал для вывода строки все IP-адреса машины. Строка просто выводится пользователю для его читать.

-module(ip).
-export([get_ip_address_string/0]).

get_ip_address_string() ->
    {ok, IPAddress} = inet:getif(),
    filter_ip_address(IPAddress).

filter_ip_address(IPAddress) ->
    filter_ip_address(IPAddress, []).

filter_ip_address([], Acc) ->
    Acc;
filter_ip_address([{{127,0,0,1}, _Broadcast, _Mask} | Tail], Acc) ->
    %Do not include the loopback address.
    filter_ip_address(Tail, Acc);
filter_ip_address([Head | Tail], Acc) ->
    {{Oct1, Oct2, Oct3, Oct4}, _Broadcast, _Mask} = Head,
    IPString = io_lib:format("~b.~b.~b.~b ", [Oct1, Oct2, Oct3, Oct4]),
    filter_ip_address(Tail, IPString ++ Acc).

Комментарии о как написать это в более Эрланг сторону, сделать его более читабельным, или все, что вы могли бы сделать другой приветствуются.



Комментарии
2 ответа

Во-первых переменной IP-адрес не отвечает действительности. Это звучит так, как если бы он содержал один IP-адрес, но на самом деле он содержит список из нескольких троек, где каждый не только содержать IP-адрес, а также соответствующий широковещательный адрес и маска подсети. Вы должны, вероятно, назвать это что-то вроде IPTriples.

Если вы посмотрите на код, это в основном делают три вещи:


  1. Отфильтровывая от localhost

  2. Замена каждого IP-адреса в строковое представление

  3. Связывая, таким образом, создается список строк, разделяя их пробелами.

Для каждого из этих 3 шагов уже есть функция Эрланга, который может быть использован, чтобы сделать это:


  1. списки:фильтр , который принимает предикат и список, и возвращает список, содержащий только элементы, которые соответствуют этому предикату.

  2. списки:карта , которая принимает функцию и список, и возвращает список, содержащий результат выполнения функции для каждого элемента.

  3. строку:присоединяйся , которая принимает список строк и разделитель и возвращает строку для каждого элемента в списке, разделенных разделителем.

Как правило, это хороший метод, чтобы повторно использовать как можно больше имеющихся функций, а не переопределить его. Таким образом, используя эти функции, ваш get_ip_address_string можно переписать на что-то вроде этого:

get_ip_address_string() ->
{ok, IPTriples} = inet:getif(),
FilteredIPTriples = lists:filter(fun is_not_localhost/1), IPTriples),
IPAddresses = lists:map(fun ip_triple_to_string/1, FilteredIPTriples),
string:join(IPAddresses, " ").

is_not_localhost({{127,0,0,1}, _Broadcast, _Mask}) -> false;
is_not_localhost({_IP, _Broadcast, _Mask}) -> true.

ip_triple_to_string({{Oct1, Oct2, Oct3, Oct4}, _Broadcast, _Mask}) ->
io_lib:format("~b.~b.~b.~b", [Oct1, Oct2, Oct3, Oct4]).

Обратите внимание, что это также благо, что логику фильтрации на localhost, логика для превращения IP-адресов в строки и логику для формирования строки результат от этого уже не переплетены, что должен сделать код более управляемым.

6
ответ дан 23 февраля 2011 в 12:02 Источник Поделиться

Мое решение близко к sepp2k это:

Первый более простой процедуру преобразования:

ip_triple_to_string(Tup) ->
io_lib:format("~b.~b.~b.~b", tuple_to_list(Tup)).

Потом мясо:

get_ip_address_string() ->
{ok, IPTriples} = inet:getif(),

Не так много вы можете сделать здесь. Вы должны утверждать, что вы действительно получили сведения от getif версии/0 звонок.

    Strings = [ip_triple_to_string(IP) || {IP, _, _} <- IPTriples,
IP =/= {127,0,0,1}],
string:join(Strings, " ").

Постижение список захватывает карте и фильтра в одном пройдемся по списку. В противном случае, это очень похоже на другие определения.

6
ответ дан 23 февраля 2011 в 02:02 Источник Поделиться