在Wi-Fi Direct场景下如何获取每个设备的IP地址?

20
从ICS开始,引入了Wi-Fi Direct技术。通常我们使用WifiP2pManager类来操作Wi-Fi Direct,但是它似乎只能在连接后检索GroupOwner IP地址。实际上,任何设备都可以协商成为GroupOwner。在上层应用中,我们需要获取对等设备的IP地址,或者组中每个对等设备的IP地址,以便与它们进行发送/通信。
如何获取Wi-Fi Direct中的每个IP地址?包括自己的IP地址和群组中的每个对等设备的IP地址?
6个回答

19

我遇到了相同的问题。由于两个设备都知道组所有者的IP地址,所以已经可以向组所有者发送消息。您发送的第一条消息可以包含另一个设备的IP地址; 从那时起,双向通信就成为可能。

以下是在Java中检索您的IP地址的可能方式:

private byte[] getLocalIPAddress() {
    try { 
        for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) { 
            NetworkInterface intf = en.nextElement(); 
            for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) { 
                InetAddress inetAddress = enumIpAddr.nextElement(); 
                if (!inetAddress.isLoopbackAddress()) { 
                    if (inetAddress instanceof Inet4Address) { // fix for Galaxy Nexus. IPv4 is easy to use :-) 
                        return inetAddress.getAddress(); 
                    } 
                    //return inetAddress.getHostAddress().toString(); // Galaxy Nexus returns IPv6 
                } 
            } 
        } 
    } catch (SocketException ex) { 
        //Log.e("AndroidNetworkAddressFactory", "getLocalIPAddress()", ex); 
    } catch (NullPointerException ex) { 
        //Log.e("AndroidNetworkAddressFactory", "getLocalIPAddress()", ex); 
    } 
    return null; 
}

private String getDottedDecimalIP(byte[] ipAddr) {
    //convert to dotted decimal notation:
    String ipAddrStr = "";
    for (int i=0; i<ipAddr.length; i++) {
        if (i > 0) {
            ipAddrStr += ".";
        }
        ipAddrStr += ipAddr[i]&0xFF;
    }
    return ipAddrStr;
}

ip = getDottedDecimalIP(getLocalIPAddress());

将该IP地址包装在可序列化的对象中,像发送任何其他对象一样将其发送到组所有者。将其视为WiFi Direct协议的第一步...现在,组所有者也有一个IP可以用来发送回答。

这对我有效,虽然我认为自己必须亲自实现并且只能轻松找到组所有者IP(info.groupOwnerAddress.getHostAddress(); //其中info是WifiP2pInfo实例),这有点奇怪。也许还有一种类似的方法来检索其他对等方的IP,但我找不到。如果您找到了,请与我联系。

祝好运...


5
警告:此代码返回第一个非环回IP地址,如果您同时连接到wifi接入点和wifi直连,则可能会返回接入点的地址。根据我所见,Wifi直连使用的网络是192.168.49.0范围,因此您应该检查它是否在该范围内,或者更好的方法是比较所有者的主机地址以确保他们在同一网络上。 - triggs
从过去的论坛帖子中,我发现如果我可以创建一个TCP连接,那么主机(组所有者)可以获取客户端IP。但是对于UDP连接,如何获取客户端IP地址呢?谢谢。 - user1850484

13

你可能能得到的最好答案可能来自Mano:

我遇到了同样的问题。由于两个设备都知道组所有者的IP地址,因此已经可以向组所有者发送消息。您发送的第一条消息可以包含另一个设备的IP地址;从那时起,双向通信就成为可能了。

这是我如何实现的。当我通过WiFi Direct将客户端连接到组所有者时,我会获取组所有者的IP地址,并通过套接字向组所有者发送消息。类似这样:

Socket socket = new Socket();
socket.setReuseAddress(true);
socket.connect((new InetSocketAddress(mIP, mPort)), SOCKET_TIMEOUT);
OutputStream os = socket.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(new String("BROFIST");
oos.close();
os.close();
socket.close();
你已经知道mIP(组所有者的IP地址),只需要决定一个mPort并在组所有者上接收连接,像这样:

You already know mIP (the group owner's IP address), and only have to decide a mPort and receive the connection on the group owner like this:

Socket serverSocket = new ServerSocket(mPort);
serverSocket.setReuseAddress(true);
Socket client = serverSocket.accept();
ObjectInputStream objectInputStream = new ObjectInputStream(client.getInputStream());
Object object = objectInputStream.readObject();
if (object.getClass().equals(String.class) && ((String) object).equals("BROFIST")) {
  Log.d(TAG, "Client IP address: "+client.getInetAddress());
}

这是我正在使用的实际代码。我将用一些有用的信息替换这条消息,比如一个包含发送方MAC地址的消息对象,可以用来了解MAC-IP关系,因为WifiP2pDevice只提供MAC地址而InetAddress提供IP地址(是否有办法从一个InetAddress对象中获取MAC地址?)。


我也遇到了同样的问题,搜索了很多资料最终还是采用了同样的方法。这似乎是最好的方式,不依赖于某些内部系统接口,因此未来看起来不容易中断! - xuiqzy

5
我已经完成了一个示范项目,可以获取每个设备的IP,并从一个设备发送数据到另一个设备(无论是否是组所有者)。该网址是:https://github.com/ahmontero/wifi-direct-demo。希望对您有所帮助!编辑:基本上可以像这样在ARP缓存中查找IP地址:
public static String getIPFromMac(String MAC) {
    BufferedReader br = null;
    try {
        br = new BufferedReader(new FileReader("/proc/net/arp"));
        String line;
        while ((line = br.readLine()) != null) {

            String[] splitted = line.split(" +");
            if (splitted != null && splitted.length >= 4) {
                // Basic sanity check
                String device = splitted[5];
                if (device.matches(".*p2p-p2p0.*")){
                    String mac = splitted[3];
                    if (mac.matches(MAC)) {
                        return splitted[0];
                    }
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return null;
}

5
这个方法来自你下面提供的网址的项目...我尝试使用这个应用程序...但是它没有起作用...另外还发生了两次崩溃...我不能推荐任何人尝试使用这种方法...因为它总是返回null。 - Volodymyr Yatsykiv
我能够只检索到连接的WiFi网络的值,但它没有提供WiFi Direct的值。 - Teja
这段代码运行很好。我能够检索到连接的WiFi Direct IP地址。 - Teja
1
@ Teja:你能进一步解释一下,你是如何检索连接的WiFi Direct IP地址的吗?因为我只能获取WiFi网络的IP地址,而不是WiFi Direct的。 - user1850484
1
这似乎非常粗糙且容易出错。 - xuiqzy

2

我有另一种方法!

当您在两个(或更多)设备之间创建连接时,无法设置谁是所有者,谁是客户端。

唯一的信息是当 BroadCast 接收器连接时,您会接收到一个“WifiP2pInfo”对象。此对象包含两个有趣的信息:

  • 所有者 IP 地址 (mWifiP2PInfo.groupOwnerAddress)。这个字符串以“/”开头。不要忘记将其删除! ;)
  • 您是否是所有者 (mWifiP2PInfo.isGroupOwner)

从那里,您拥有了所需的所有内容!

如果您是群主 => 监听连接

否则,请使用 IP 地址向所有者创建连接。

if (mWifiP2PInfo.isGroupOwner) {
    serverSocket = new ServerSocket(port);
    socket = serverSocket.accept();
} else {
    // If the client is not listening when the server create the connection, the connection is not established => Try again
    int retry = 10;

    socket = new Socket();
    socket.bind(null);
    do {
        socket.connect((new InetSocketAddress(mWifiP2PInfo.groupOwnerAddress, port)), 500);
        retry--;
    } while (!socket.isConnected() && retry > 0);
}

希望能对您有所帮助!

2
我已经能够在WiFi直连网络中进行双向连接和发送。 所有设备都知道组主的IP地址。我们通过为通信创建的套接字获取对等方IP。但是,在服务器端(组主)从套接字获取IP并不起作用。因此,我从设备本身向组主发送了个体设备的IP。要获取IP,只需创建一个套接字并将其绑定到任何本地端口,然后从该套接字获取地址并将其发送给组主。 我使用了UDP套接字,但与TCP套接字一样有效。
DatagramSocket socket=null;
     try {
        socket=new DatagramSocket();
        socket.connect((new InetSocketAddress(host, port)));
        String address=socket.getLocalAddress().getHostAddress();
        ByteBuffer bb=ByteBuffer.allocate(2+address.length());
        bb.putChar('I');
        bb.put(address.getBytes());
        DatagramPacket pkt=new DatagramPacket(bb.array(),2+address.length());
        socket.send(pkt);
        Log.d(WiFiDirectActivity.TAG,"address"+address+"dest"+host);
        Log.d(WiFiDirectActivity.TAG,"send");
    } catch (SocketException e) {
        Log.e(WiFiDirectActivity.TAG,"error socketException");
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        if (socket != null) {
            if (socket.isConnected()) {
                socket.close();
            }
    }

host 是从连接信息中获取的组所有者的地址。


谢谢。我有主机IP,但我需要放置在端口号中的内容是什么?在应用程序中,我正在使用8000。我可以使用它吗? - Teja

1
请使用这种方法获取IP地址。
  public static String getIpAddress() {
    try {
        List<NetworkInterface> interfaces = Collections
                .list(NetworkInterface.getNetworkInterfaces());
        /*
         * for (NetworkInterface networkInterface : interfaces) { Log.v(TAG,
         * "interface name " + networkInterface.getName() + "mac = " +
         * getMACAddress(networkInterface.getName())); }
         */

        for (NetworkInterface intf : interfaces) {
            if (!getMACAddress(intf.getName()).equalsIgnoreCase(
                    Globals.thisDeviceAddress)) {
                // Log.v(TAG, "ignore the interface " + intf.getName());
                // continue;
            }
            if (!intf.getName().contains("p2p"))
                continue;

            Log.v(TAG,
                    intf.getName() + "   " + getMACAddress(intf.getName()));

            List<InetAddress> addrs = Collections.list(intf
                    .getInetAddresses());

            for (InetAddress addr : addrs) {
                // Log.v(TAG, "inside");

                if (!addr.isLoopbackAddress()) {
                    // Log.v(TAG, "isnt loopback");
                    String sAddr = addr.getHostAddress().toUpperCase();
                    Log.v(TAG, "ip=" + sAddr);

                    boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr);

                    if (isIPv4) {
                        if (sAddr.contains("192.168.49.")) {
                            Log.v(TAG, "ip = " + sAddr);
                            return sAddr;
                        }
                    }

                }

            }
        }

    } catch (Exception ex) {
        Log.v(TAG, "error in parsing");
    } // for now eat exceptions
    Log.v(TAG, "returning empty ip address");
    return "";
}

public static String getMACAddress(String interfaceName) {
        try {
            List<NetworkInterface> interfaces = Collections
                    .list(NetworkInterface.getNetworkInterfaces());

            for (NetworkInterface intf : interfaces) {
                if (interfaceName != null) {
                    if (!intf.getName().equalsIgnoreCase(interfaceName))
                        continue;
                }
                byte[] mac = intf.getHardwareAddress();
                if (mac == null)
                    return "";
                StringBuilder buf = new StringBuilder();
                for (int idx = 0; idx < mac.length; idx++)
                    buf.append(String.format("%02X:", mac[idx]));
                if (buf.length() > 0)
                    buf.deleteCharAt(buf.length() - 1);
                return buf.toString();
            }
        } catch (Exception ex) {
        } // for now eat exceptions
        return "";
        /*
         * try { // this is so Linux hack return
         * loadFileAsString("/sys/class/net/" +interfaceName +
         * "/address").toUpperCase().trim(); } catch (IOException ex) { return
         * null; }
         */
    }

更正:如果我是群组的拥有者,我可以获取到我的Wi-Fi直连IP地址为192.168.49.1。但是,如果我是一个客户端,就无法获取到自己的Wi-Fi直连IP地址。了解客户端IP地址非常重要,这样才有可能将此信息发送给群组拥有者。 - user1850484
如果连接建立成功,该函数99%的时间将检索任何您的WiFi直连设备的IP地址。 - Dipendra
我已经使用 "mManager.connect(mChannel, mconfig, new ActionListener() {})" 创建了连接,但是没有使用 socket 连接。在使用 socket 连接后,这段代码还能用吗? - user1850484
我想知道在代码中应该调用“String getIpAddress()”的位置。感谢Dipendra的回复。 - user1850484
从过去的论坛帖子中,我发现如果我可以创建一个TCP连接,那么主机(组所有者)可以获取客户端IP。但是对于UDP连接,如何获取客户端IP地址呢?谢谢。 - user1850484
显示剩余2条评论

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