【问题标题】:Android Wi-Fi Direct NetworkAndroid Wi-Fi 直连网络
【发布时间】:2024-01-18 05:08:01
【问题描述】:

我正在 Android 上开发一个应用程序,我正在搜索范围内的所有对等方,然后与所有对等方连接,发起发现的设备成为组所有者,所有其他设备成为客户端,我已经完成了所有操作连接的事情,但现在我想让群主将消息发送给所有连接的对等点,如何实现这一点,还请告诉我点对点通信的方法是什么,Android 中的 p2p 是否也使用 IP发送和接收数据?

谢谢你 问候塔利卜。

【问题讨论】:

  • 你的努力成功了吗?如果是,请告诉我,我面临同样的问题,无法获得解决方案。已经深入研究了所有可能的文档,但没有成功:( :(

标签: java android network-programming p2p wifi-direct


【解决方案1】:

Wi-Fi Direct/P2P 可被视为普通 Wi-Fi,但组所有者 (GO) 充当软件访问点(dhcp 服务器、配置等)。所以回答你的最后一个问题,是的,Wi-Fi Direct 也使用 IP 来发送和接收数据。

您想向群组中的所有成员发送数据吗?有两种解决方案:

  1. 使用多播将消息广播一次。
  2. 将消息发送给组中的每个单独的客户。

最有效的方法是解决方案 1,使用多播广播数据,因为您只需要发送一次数据。不幸的是,Android 中的 Wi-Fi 多​​播支持非常分散,因为许多设备似乎阻止了非单播流量。如果您想沿着这条路线走,请参阅this article 了解更多深入信息。

如果您想保证对所有设备的支持并且只传输少量数据,则解决方案 2 是最佳方法。 GO 需要组内客户端的 IP 地址,但由于 Android 中 Wi-Fi Direct 的实现方式,所有设备仅知道 GO IP。一种解决方案是让客户端连接到 GO 上的套接字,以获取其 IP 地址:

客户端代码

private static final int SERVER_PORT = 1030;

... // on group join:
wifiP2pManager.requestConnectionInfo(channel, new ConnectionInfoListener() {
    @Override
    public void onConnectionInfoAvailable(WifiP2pInfo p2pInfo) {
        if (!p2pInfo.isGroupOwner) {
            // Joined group as client - connect to GO
            Socket socket = new Socket();
            socket.connect(new InetSocketAddress(p2pInfo.groupOwnerAddress, SERVER_PORT));
        }
    }
});

群主代码:

private static final int SERVER_PORT = 1030;
private ArrayList<InetAddress> clients = new ArrayList<InetAddress>();

public void startServer() {
    clients.clear();
    ServerSocket serverSocket = new ServerSocket(SERVER_PORT);

    // Collect client ip's
    while(true) {
       Socket clientSocket = serverSocket.accept();
       clients.add(clientSocket.getInetAddress());
       clientSocket.close();
    }
}

现在您需要做的就是在每个客户端上启动一个 serversocket,并让 GO 遍历客户端列表,为每个客户端创建一个套接字连接并发送您要广播的消息。

【讨论】:

  • 这个想法很好,但在我的情况下实现不起作用。无法从群组所有者向客户端发送消息。你能帮助@nikki ashton 吗?
【解决方案2】:

现在我们有了https://github.com/libp2p/go-libp2p-pubsub - 用于处理多播消息(它也可以将网络分片为主题)

我们还有一些漂亮的对等发现协议,例如:https://github.com/libp2p/go-libp2p-examples/blob/master/chat-with-mdns/mdns.go

因此,您可以非常轻松地与本地网络中的主题消息多播进行交互,只需使用 libp2p

我刚刚测试了https://github.com/MoonSHRD/p2chat-android,它将您需要的解决方案包装到单个库中,可以在 android 中使用。

到目前为止,我们可以与高级消息交互,而不是与低级套接字或流交互。希望这会对某人有所帮助。

附言但是,我应该注意到,我还没有在 wi-fi 直接网络中测试 mDNS 发现

【讨论】:

    【解决方案3】:

    有几个选项可供选择,但您可以根据自己的要求进行选择。使用 jmdns/jmdnsbroadcastdiscover 服务相当容易。这是文档中的示例,

    • 服务注册
    import java.io.IOException;
    import java.net.InetAddress;
    
    import javax.jmdns.JmDNS;
    import javax.jmdns.ServiceInfo;
    
    public class ExampleServiceRegistration {
    
        public static void main(String[] args) throws InterruptedException {
    
            try {
                // Create a JmDNS instance
                JmDNS jmdns = JmDNS.create(InetAddress.getLocalHost());
    
                // Register a service
                ServiceInfo serviceInfo = ServiceInfo.create("_http._tcp.local.", "example", 1234, "path=index.html");
                jmdns.registerService(serviceInfo);
    
                // Wait a bit
                Thread.sleep(25000);
    
                // Unregister all services
                jmdns.unregisterAllServices();
    
            } catch (IOException e) {
                System.out.println(e.getMessage());
            }
        }
    }
    
    • 服务发现
    import java.io.IOException;
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    
    import javax.jmdns.JmDNS;
    import javax.jmdns.ServiceEvent;
    import javax.jmdns.ServiceListener;
    
    public class ExampleServiceDiscovery {
    
        private static class SampleListener implements ServiceListener {
            @Override
            public void serviceAdded(ServiceEvent event) {
                System.out.println("Service added: " + event.getInfo());
            }
    
            @Override
            public void serviceRemoved(ServiceEvent event) {
                System.out.println("Service removed: " + event.getInfo());
            }
    
            @Override
            public void serviceResolved(ServiceEvent event) {
                System.out.println("Service resolved: " + event.getInfo());
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            try {
                // Create a JmDNS instance
                JmDNS jmdns = JmDNS.create(InetAddress.getLocalHost());
    
                // Add a service listener
                jmdns.addServiceListener("_http._tcp.local.", new SampleListener());
    
                // Wait a bit
                Thread.sleep(30000);
            } catch (UnknownHostException e) {
                System.out.println(e.getMessage());
            } catch (IOException e) {
                System.out.println(e.getMessage());
            }
        }
    }
    

    如果您正在使用 java 开发桌面应用程序,您的目标应该是找到最好的跨平台 DNS-SD(Zeroconf、Bonjour、DNS 自我发现)库。

    还有其他纯 Java DNS-SD 实现,但尚不清楚它们是否提供了与 DNS-SD 一样易于使用或经过全面测试的库。前往 Waiter 一次。但是,我更喜欢通过jmdns,它运作良好。由于点对点连接应该使用 IP(它必须),因此一旦建立连接,您就可以轻松发送/接收数据。

    【讨论】:

      最近更新 更多