Erlang: 寻找我的 IP 地址

6

我正在尝试使用Redis完成负载均衡/登录服务器/游戏服务器的设置,其中一部分是负载均衡。在我的Redis负载均衡实例中,我使用有序集合。键是应用程序名称,成员是游戏服务器的IP地址。

这里出现了问题。我想在erlang中使用公共方法,但找不到符合我的需求的东西。我想知道是否有什么我忽略了的东西。

{ok, L} = inet:getif(),
IP = element(1, hd(L)),

能够给我我想要的东西。我相信目前它是{192,168,0,14}。但该函数不是“公共的”。

{ok, Socket} = gen_tcp:listen(?PORT_LISTEN_GAME, [{active,once}, {reuseaddr, true}]),
{ok, {IP, _} = inet:sockname(Socket),

给我 {0,0,0,0}。我尝试了 inet:getaddr("owl"),它给了我 {127,0,1,1}。
我只能通过TCP发送消息并使用inet:peername(Socket)吗?看起来要做这么简单的事情需要很多步骤。我的应用程序的所有不同部分都在同一台计算机上进行测试。它会给我返回{127,0,0,1}吗?那行不通。我需要将IP地址发送回用户(我的手机),以便他们可以连接到正确的服务器。回环是不行的... 当前代码 感谢所有的回复。是的,我注意到Lol4t0在新年后的评论。所以我改变了我的代码来反映这一点。为像我这样的慢人发布这个。我必须费一些脑筋才能让这些东西点击。
hd([Addr || {_, Opts} <- Addrs,
    {addr, Addr} <- Opts,
    {flags, Flags} <- Opts,
    lists:member(loopback,Flags) =/= true]).
3个回答

8
我们一直成功地使用这个函数来获取第一个非本地的IPv4地址:
local_ip_v4() ->
    {ok, Addrs} = inet:getifaddrs(),
    hd([
         Addr || {_, Opts} <- Addrs, {addr, Addr} <- Opts,
         size(Addr) == 4, Addr =/= {127,0,0,1}
    ]).

如果您需要,当然可以将其更改为返回IPv6。


我一开始在研究proplists,但这种方法更受欢迎。我对以这种方式构建列表不太熟悉。谢谢。我稍微修改了一下。也许你会更喜欢这个版本。 :)我的问题是它正在获取下一个(ipv6)环回...虽然如果我使用您的大小约束,就不会发生这种情况。 - Nolan Robidoux
返回已翻译的文本:hd([Addr || {IF,Opts} <- Addrs,{addr,Addr} <- Opts,IF =/=“lo”]). - Nolan Robidoux
@NolanRobidoux 这可以随机给出IPv4和IPv6,而且不考虑像lo0这样的接口名称。 - Adam Lindberg
我猜无论如何使用它,总会有一些微调。对我来说,只要我的手机能与电脑通信,我不在乎是IPv4还是IPv6。 :) - Nolan Robidoux
@NolanRobidoux,“我遇到的问题是它正在获取下一个(ipv6)回送地址”,你只需检查_flags_而不是应用hack。 - Lol4t0

2
你需要先了解,你的主机可能有多个唯一的IP地址。事实上,所有的{0,0,0,0}{127,0,0,1}(嘿!实际上所有的127.0.0.0/8都是你的地址)和{192,168,0,14}都是你的有效IP地址。此外,如果你的主机连接了其他接口,你将获得更多的IP地址。因此,你基本上找不到一个函数可以获取你需要的IP地址。
相反,在inet模块中有一个被充分记录的函数,它会列出每个接口及其自己的IP地址:
getifaddrs() -> {ok, Iflist} | {error, posix()}

Types:

Iflist = [{Ifname, [Ifopt]}]
Ifname = string()
Ifopt = {flag, [Flag]}
      | {addr, Addr}
      | {netmask, Netmask}
      | {broadaddr, Broadaddr}
      | {dstaddr, Dstaddr}
      | {hwaddr, Hwaddr}
Flag = up
     | broadcast
     | loopback
     | pointtopoint
     | running
     | multicast
Addr = Netmask = Broadaddr = Dstaddr = ip_address()
Hwaddr = [byte()]

谢谢。我应该继续查看在线Erlang手册列表。我知道每个接口都有一个IP :) 我只需要一个有效的且唯一的IP地址(即不是任何环回地址),这样我的手机才能与之通信,并且游戏服务器实例可以得到适当的速率限制。这符合要求。 - Nolan Robidoux
不过它没有列出我的IPv6。 - Thomas Browne

0

使用 OTP 中的 getifaddr() 函数可以获取机器上所有可用接口的详细列表。下面的解决方案应该能够消除许多对Erlang感到困惑的新手,因为它也曾经困扰过我。这个函数并不是最优化的,但非常易读,并且可以给你一个本地IP4地址,就像你在局域网派对上使用的那种:

 %Get the local IP4 address of this machine in the local network (LAN party address)
local_ip_v4() ->
  {ok, IntfList} = inet:getifaddrs(), %Get a list of all interfaces (Wifi, Lan, Internal loopback etc)

  %Filter this list to look for an interface that is "up and running" (has a connection) 
   SelectedInf = lists:foldl( fun(El, SelectedIf)->
                {InfName,InfOpts} = El,
                Flags = lists:keyfind(flags,1,InfOpts),
                case Flags of
                  {flags,[up,running]} ->
                    {InfName,InfOpts};
                  _->
                    SelectedIf
                end
                end,
                none,IntfList),

  io:format("~n INTERFACES: ~p ",[IntfList]),
  io:format("~n Selected INTERFACE: ~p ",[SelectedInf]),

  %Look through this interface's properties for the addresses, but only match one
  % that has 4 components in the tuple!
  {Sel_InfName,Sel_InfOpts} = SelectedInf,
  Address_I4 = lists:foldl( fun(El,Addr)->
                              case El of
                                {addr,{A,B,C,D}}->
                                  {A,B,C,D};
                                _->
                                  Addr
                              end
                            end, none, Sel_InfOpts),
  io:format("~n Selected INTERFACE IP4: ~p ~n",[Address_I4]),
  Address_I4.

希望这有所帮助 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接