微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Android 和 C++ 套接字通过 WiFi Direct 通信

如何解决Android 和 C++ 套接字通过 WiFi Direct 通信

概述:我目前正在开发一个 Android 应用,该应用通过 WiFi Direct 连接到 Linux 系统,最终目的是通过此已建立的连接流式传输视频。

在这种情况下,raspi 将充当服务器,而 Android 作为客户端。我将从连接到 pi 的相机进行流式传输,并在 Android 端接收此视频以使用 ExoPlayer 在我的应用程序中显示。如果没有客户端的 IP 地址,pi 无法开始通过数据报套接字发送此视频。 Android 设备还需要向 Pi 发送杂项数据包,这些数据包会告诉它要做什么,因此两个设备都需要拥有彼此的 IP 地址。

我目前使用的 Linux 系统是运行 Raspian 的 RaspBerry Pi,使用 C++ 进行开发。 Android 运行时环境是 Samsung galaxy Tab A。

问题:我能够成功地在两台设备之间建立连接,我已经设置了连接,因此 RaspBerry Pi 始终是组所有者。由于 Pi 是组所有者,它无法立即访问 Android 的 IP 地址;因此必须在两者之间建立一个临时的 TCP 套接字连接,以便 RaspBerry Pi 可以记录 Android 的 IP 地址。

建立 WiFi 连接后,此 C++ 代码在 Pi 上运行以打开并接受来自 Android 的 TCP 套接字连接:

#include<cstddef>
#include<iostream>
#include<string>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/un.h>
#include<unistd.h>
#include<netdb.h>
#include<netinet/in.h>
#include<arpa/inet.h>

#define BACKLOG 2 //Allowed connection count.

#define PORT 8988 //The port we will be listening on.

//The static IP of p2p-dev-wlan0
const std::string MY_IP = "192.168.4.1";

bool listen_for_ip() {

    //Buffer for receiving messages.
    char buffer[256];

    //Create Server Socket:
    int sock_fd = socket(AF_INET,SOCK_STREAM,0);
    if (sock_fd < 0)
        return false;
    else
        std::cout << "Created Server" << std::endl;

    struct sockaddr_in my_addr,peer_addr;

    //Recieve messages from IPv4 addresses.
    my_addr.sin_family = AF_INET;

    //Set our IP address of the socket to the value in "MY_IP"
    my_addr.sin_addr.s_addr = inet_addr(MY_IP.c_str());
    //my_addr.sin_addr.s_addr = INADDR_ANY; // Also tested with this,no luck.

    //Set our in port to the value in "PORT"
    my_addr.sin_port = htons(PORT);

    //Attempt to bind to IP and port.
    if (bind(sock_fd,(struct sockaddr*) &my_addr,sizeof(my_addr)) == 0)
        std::cout << "Binded successfully" << std::endl;
    else
        return false;

    //Listen on the socket
    if (listen(sock_fd,BACKLOG) < 0)
        return false;

    //Accept a connection.
    socklen_t peer_addr_size = sizeof(peer_addr);
    std::cout << "Accepting connection ..." << std::endl;
    int new_fd = accept(sock_fd,(struct sockaddr*) &peer_addr,&peer_addr_size);
    if (new_fd == -1) {
        std::cout << "Error accepting connect" << std::endl;
        close(sock_fd);
        return false;
    }
    else
        std::cout << "Connection accept completed status = " << new_fd << std::endl;

    //
    char ip[INET_ADDRSTRLEN];
    inet_ntop(AF_INET,&(peer_addr.sin_addr),ip,INET_ADDRSTRLEN);
    if (recv(new_fd,buffer,256,0) < 0) {
        close(new_fd);
        close(sock_fd);
        return false;
    }

    std::cout << "Client says " << buffer << std::endl;

    //Do other stuff with connection ...

    close(new_fd);
    close(sock_fd);
    return true;
}

代码成功运行,并且 as should 阻塞了 accept() 调用以等待 Android 连接到套接字。

在 Android 端,运行此代码以通过基本套接字连接到 Pi(组所有者):

public static final int PORT = 8988;

private static final int TIMEOUT_MS = 10000;

private final String myIp;

private wifip2pInfo mGroupInfo;

private final WifiDirectService mWifiDirectService;

public P2pClientSocket(WifiDirectService wifiDirectService,wifip2pInfo groupInfo,String ourDeviceIP) {
    mGroupInfo = groupInfo;
    myIp = ourDeviceIP;
    mWifiDirectService = wifiDirectService;
    exchangeIP();
}

/**
 * Utilizes a basic socket & TCP to ensure that the IP address of this machine is sent to the group owner of established P2P group.
 * If there is an error with sending or writing this message,or the message times out,* {@link WifiDirectService} will be notified to immediately dispose of its current connection.
 */
private void exchangeIP()  {
    Socket initSocket = new Socket();
    Runnable r = () -> {
        try {
            String host = mGroupInfo.groupOwnerAddress.getHostAddress();
            Log.d(TAG,"opening socket to : " + host + "," + PORT);
            initSocket.connect(new InetSocketAddress(host,PORT),TIMEOUT_MS);
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(initSocket.getoutputStream(),StandardCharsets.UTF_8);
            outputStreamWriter.write(myIp,myIp.length());
            outputStreamWriter.close();
            Log.d(TAG,"Successfully wrote IP.");
        } catch (SocketTimeoutException e) {
            String message = "Connection Timeout - disconnecting.";
            Log.e(TAG,message,e);
            mWifiDirectService.socketError(message);
        } catch (IOException e) {
            String message = "IP Exchange Error - disconnecting.";
            Log.e(TAG,e);
            mWifiDirectService.socketError(message);
        } finally {
            try {
                initSocket.close();
            } catch (IOException e) {
                Log.e(TAG,"Error Closing Init Socket.");
            }
        }
    };
    new Thread(r).start();
}

价值 String host = mGroupInfo.groupOwnerAddress.getHostAddress() 将始终是树莓派的 IP 地址。我已经对其进行了配置,使其作为具有静态 IP 的 DHCP 服务器运行:

cat > /etc/systemd/network/12-p2p-wlan0.network <<EOF 
[Match] 
Name=p2p-wlan0-* 
[Network] 
Address=192.168.4.1/24 
DHcpserver=yes 

EOF

但是,在 .connect() 调用中,总是达到超时阈值。我有点网络菜鸟,所以我不完全确定我做错了什么。包括超时堆栈跟踪:

java.net.socketTimeoutException: Failed to connect to /192.168.4.1 (port 8988) from /192.168.4.163 (port 33122) after 10000ms
        at libcore.io.IoBridge.connectErrno(IoBridge.java:191)
        at libcore.io.IoBridge.connect(IoBridge.java:135)
        at java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:142)
        at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:390)
        at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:230)
        at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:212)
        at java.net.socksSocketImpl.connect(SocksSocketImpl.java:436)
        at java.net.socket.connect(Socket.java:621)
        at com.nlos.networking.P2pClientSocket.lambda$exchangeIP$0$P2pClientSocket(P2pClientSocket.java:54)
        at com.nlos.networking.-$$Lambda$P2pClientSocket$fxU2Z0Zg0gRF1Fyl1fNnqgO2m8I.run(UnkNown Source:4)
        at java.lang.Thread.run(Thread.java:919)

我尝试了多个不同的套接字,确保 pi 确实在监听,并且老实说在这一点上被难住了。任何帮助将不胜感激!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。