【问题标题】:Send a string through WiFi-Direct between two android devices在两个安卓设备之间通过 WiFi-Direct 发送字符串
【发布时间】:2019-12-27 23:33:45
【问题描述】:

现在已经一个多月了,我试图在两个安卓设备之间使用 WiFi-Direct 发送一个字符串,但我仍然很难理解我做错了什么。

我浏览了论坛,但他们通常没有详细说明如何实现我想要的。

我还浏览了 android 开发者网站上的这两个指南:

我正在使用一项活动 - ActivityConnection - 我根据用户之前是选择发送还是接收字符串来切换视图的可见性。

  • 立即,在客户端,discoverPeers() 查找任何打开了 WiFi-Direct 的设备并将它们显示在 ListView 上。一旦用户选择了一个设备并按下发送按钮,连接就会自行建立并发送字符串。

  • 在服务器端,使用我的AsyncServerTask 类立即启动服务器。在那里,它等待客户端连接并检索其发送的字符串。

我的主要问题是,在选择设备并点击发送按钮后,服务器端没有收到任何内容。 我的第二个问题是,有时没有发现设备并且列表视图保持为空。

我错过了什么吗?或者可能做错了什么?

这是我当前的代码。 我冒昧地删除了我认为与上下文无关的任何行,以使其更易于阅读。

ActivityConnection

public class ActivityConnection extends AppCompatActivity implements NewPeersListener {

    public static final String CONNECTION_ACTOR = "actor";
    public static final String SEND_INFO = "send";
    public static final String RECEIVE_INFO = "receive";

    ListView listViewDevices;

    private IntentFilter intentFilter;
    private WifiP2pManager manager;
    private WifiP2pManager.Channel channel;
    private WiFiDirectBroadcastReceiver receiver;

    public List <WifiP2pDevice> listDevices;
    private WifiP2pDevice selectedDevice;



    @Override
    public void onCreate (Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        confirm.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                connectToSelectedDevice();
            }
        });

        Intent intent = this.getIntent();
        String actor = intent.getStringExtra(CONNECTION_ACTOR);

        this.intentFilter = new IntentFilter();
        this.intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
        this.intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
        this.intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
        this.intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);

        this.manager = (WifiP2pManager) this.getSystemService(Context.WIFI_P2P_SERVICE);
        this.channel = this.manager.initialize(this, this.getMainLooper(), null);
        this.receiver = new WiFiDirectBroadcastReceiver(this.manager, this.channel, this);

        this.listDevices = new ArrayList <> ();

        if (actor.equals(SEND_INFO)) {
            DeviceAdapter adapter = new DeviceAdapter(ActivityConnection.this, R.layout.device_item, this.listDevices);
            this.listViewDevices.setAdapter(adapter);

            this.listViewDevices.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    selectedDevice = listDevices.get(position);
                }
            });

            this.discoverPeers();
        }
        else if (actor.equals(RECEIVE_INFO)) {
            new ServerAsyncTask(this).execute();
        }
    }



    @Override
    protected void onResume() {
        super.onResume();
        this.receiver = new WiFiDirectBroadcastReceiver(this.manager, this.channel, this);
        this.registerReceiver(this.receiver, this.intentFilter);
    }

    @Override
    protected void onPause() {
        super.onPause();
        this.unregisterReceiver(this.receiver);
    }



    public void resultReceived (String result) {
        Toast.makeText(ActivityConnection.this, "Received! :)", Toast.LENGTH_SHORT).show();
    }



    private void discoverPeers () {
        manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
            @Override
            public void onSuccess() {
                // The discovery process succeeded
            }

            @Override
            public void onFailure(int reason) {
                // The discovery process DID NOT succeed
                Toast.makeText(ActivityConnection.this, "Discovery process DID NOT succeed. Please verify that WiFi-Direct is active.", Toast.LENGTH_LONG).show();
            }
        });
    }



    private void connectToSelectedDevice () {
        WifiP2pConfig config = new WifiP2pConfig();
        config.deviceAddress = this.selectedDevice.deviceAddress;
        this.manager.connect(this.channel, config, new WifiP2pManager.ActionListener() {
            @Override
            public void onSuccess() {
                // Send string
                Intent serviceIntent = new Intent(ActivityConnection.this, TransferService.class);
                serviceIntent.setAction(TransferService.ACTION_SEND_STRING);
                serviceIntent.putExtra(TransferService.EXTRAS_GROUP_OWNER_ADDRESS, getMacAddress());
                serviceIntent.putExtra(TransferService.EXTRAS_GROUP_OWNER_PORT, 8090);
                startService(serviceIntent);
                onBackPressed();
            }

            @Override
            public void onFailure(int reason) {
                Toast.makeText(ActivityConnection.this, "Connection failed. Try again.", Toast.LENGTH_SHORT).show();
            }
        });
    }



    @NonNull
    private String getMacAddress () {
        try {
            List <NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface nif : all) {
                if (!nif.getName().equalsIgnoreCase("wlan0")) continue;

                byte[] macBytes = nif.getHardwareAddress();
                if (macBytes == null) {
                    return "";
                }

                StringBuilder result = new StringBuilder();
                for (byte b : macBytes) {
                    result.append(String.format("%02X:",b));
                }

                if (result.length() > 0) {
                    result.deleteCharAt(result.length() - 1);
                }
                return result.toString();
            }
        } catch (Exception e) {
        }
        return "02:00:00:00:00:00";
    }



    @Override
    public void newPeers (WifiP2pDeviceList wifiP2pDeviceList) {
        this.listDevices = new ArrayList <> (wifiP2pDeviceList.getDeviceList());
        DeviceAdapter adapter = new DeviceAdapter(ActivityConnection.this, R.layout.device_item, this.listDevices);
        this.listViewDevices.setAdapter(adapter);
    }
}

WiFiDirectBroadcastReceiver

public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {

    private WifiP2pManager manager;
    private WifiP2pManager.Channel channel;
    private ActivityConnection activity;

    private List <NewPeersListener> listeners;



    public WiFiDirectBroadcastReceiver(WifiP2pManager manager, WifiP2pManager.Channel channel, ActivityConnection activity) {
        super();
        this.manager = manager;
        this.channel = channel;
        this.activity = activity;

        this.listeners = new ArrayList <> ();
        this.listeners.add(activity);
    }



    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();

        if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
            int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
            if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
                // Wi-Fi P2P is enabled
            } else {
                // Wi-Fi P2P is not enabled
                Toast.makeText(this.activity, "Please turn on WiFi-Direct (or WiFi-P2P).", Toast.LENGTH_SHORT).show();
            }

        } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
            // Request available peers from the wifi p2p manager.
            if (this.manager != null) {
                this.manager.requestPeers(this.channel, new WifiP2pManager.PeerListListener() {
                    @Override
                    public void onPeersAvailable(WifiP2pDeviceList peers) {
                        for (NewPeersListener listener : listeners) {
                            listener.newPeers(peers);
                        }
                    }
                });
            }
        } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
            // Respond to new connection or disconnections
        } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
            // Respond to this device's wifi state changing
        }
    }

}

ServerAsyncTask(服务器)

public class ServerAsyncTask extends AsyncTask<Void, Void, String> {

    private ServerSocket serverSocket;
    private Socket clientSocket;
    private DataInputStream stream;

    private WeakReference <Context> contextWeakReference;



    ServerAsyncTask (Context context) {
        this.contextWeakReference = new WeakReference <> (context);
    }



    @Override
    protected String doInBackground (Void... params) {
        try {
            this.serverSocket = new ServerSocket(8090);
            this.clientSocket = this.serverSocket.accept();

            this.stream = new DataInputStream(this.clientSocket.getInputStream());
            String received = this.stream.readUTF();
            this.serverSocket.close();
            return received;
        } catch (IOException e) {
            Log.e(TransferService.TAG, Objects.requireNonNull(e.getMessage()));
            return null;
        } finally {
            if (this.stream != null) {
                try {
                    this.stream.close();
                } catch (IOException e) {
                    Log.e(TransferService.TAG, Objects.requireNonNull(e.getMessage()));
                }
            }
            if (this.clientSocket != null) {
                try {
                    this.clientSocket.close();
                } catch (IOException e) {
                    Log.e(TransferService.TAG, Objects.requireNonNull(e.getMessage()));
                }
            }
            if (this.serverSocket != null) {
                try {
                    this.serverSocket.close();
                } catch (IOException e) {
                    Log.e(TransferService.TAG, Objects.requireNonNull(e.getMessage()));
                }
            }
        }
    }

    /*
     * (non-Javadoc)
     * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
     */
    @Override
    protected void onPostExecute (String result) {
        super.onPostExecute(result);
        ((ActivityConnection) this.contextWeakReference.get()).resultReceived(result);
    }

}

TransferService(客户端)

public class TransferService extends IntentService {

    public static final String TAG = "WIFI_DIRECT";

    private static final int SOCKET_TIMEOUT = 5000;
    public static final String ACTION_SEND_STRING = "sendString";
    public static final String EXTRAS_GROUP_OWNER_ADDRESS = "go_host";
    public static final String EXTRAS_GROUP_OWNER_PORT = "go_port";



    public TransferService (String name) {
        super(name);
    }

    public TransferService () {
        super("TransferService");
    }



    @Override
    protected void onHandleIntent (Intent intent) {
        Context context = getApplicationContext();
        if (intent.getAction().equals(ACTION_SEND_STRING)) {
            String toSend = "string to send";

            String host = intent.getExtras().getString(EXTRAS_GROUP_OWNER_ADDRESS);
            int port = intent.getExtras().getInt(EXTRAS_GROUP_OWNER_PORT);
            Socket socket = null;
            DataOutputStream stream = null;
            try {
                // Create a client socket with the host, port, and timeout information.
                socket = new Socket();
                socket.bind(null);
                socket.connect((new InetSocketAddress(host, port)), SOCKET_TIMEOUT);
                Log.d(TAG, "Client connected socket - " + socket.isConnected());

                // Send string
                stream = new DataOutputStream(socket.getOutputStream());
                stream.writeUTF(toSend);
                stream.close();
                Toast.makeText(context, "Sent! :)", Toast.LENGTH_SHORT).show();
            } catch (IOException e) {
                Log.e(TAG, Objects.requireNonNull(e.getMessage()));
            } finally {
                if (stream != null) {
                    try {
                        stream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (socket != null) {
                    if (socket.isConnected()) {
                        try {
                            socket.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}

【问题讨论】:

  • 当您能够建立链接时,您是否尝试过在 Android 终端模拟器 (play.google.com/store/apps/…) 中运行类似ip a 的网络命令。像 Android 中的许多其他问题一样,这可能是权限问题。你的机器人扎根了吗?
  • 还有一点是封闭的端口。当我 nmap 我的 Android 端口 8090 关闭并且我有默认配置时
  • 也许在 Android Terminal Emulator shell 中尝试ping通过 Wifi Direct 连接的手机
  • @ralfhtp 感谢您的帮助和时间。我终于设法找出问题所在并写下了答案。

标签: java android wifi-direct wifimanager wifip2p


【解决方案1】:

ActivityConnetion 类中,我提供的是 MAC 地址而不是 IP 地址。我不知道为什么我没有看到这一点,也不知道为什么我一开始就这样做了。于是我翻遍了这个论坛,发现了如何获取WiFi-Direct群主的IP地址:Wifi Direct Group Owner Address

为了让代码运行,我进入ActivityConnetion类,删除getMacAddress()方法并替换这一行:

serviceIntent.putExtra(TransferService.EXTRAS_GROUP_OWNER_ADDRESS, getMacAddress());

用这一行:

serviceIntent.putExtra(TransferService.EXTRAS_GROUP_OWNER_ADDRESS, "192.168.49.1");

由于群主的IP始终相同,可以直接写下来。如果 IP 发生变化,这样做可能会停止工作,我建议改为寻找组所有者的 IP。上面的链接显示了如何做到这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-15
    相关资源
    最近更新 更多