-->

Android Wifi Roaming through AP with same SSID

2019-07-26 00:09发布

问题:

I saw that Android system has a bad behavior with Wifi roaming. We have a Wifi centralized network with many AP with a signle SSID. The Adroid Phones wont roams seamlessly. An Android Phone tries to stay connected to an AP until the signal reaches zero even if there are others AP (with the same SSID) with a good signal! When the signal is zero, finally it performs an assosiation to another AP (with a good signal). But with this behavior the phone loses all the TCP Connections!

For example:

  1. the phone is connected in WiFi to AP1
  2. the phone moves in the building and now hears two signals from AP1 and from AP2.
  3. When the signal form AP2 is stronger than the signal from AP1, i want that the phone do a reassosiation (not an assosiation) to AP2.

The idea is:

  • Perform a WifiManager.startScan()
  • Get the results WifiManager.getScanResults()
  • Find the best AP in the results
  • Perform a reassosiation to the best AP

Repeat every 30 seconds.

I talk about reassosiation because i don't want that the phone loses the TCP Connections.

There is a way to do this ?

Thank you, Salvo

回答1:

You cannot do this as you describe. A client cannot determine the state of the TCP connection on it's own. Your network must also move the communication channel from one AP to another. This can be done with the right network controllers.

Also, you should look at IEEE 802.11k - https://en.wikipedia.org/wiki/IEEE_802.11k-2008



回答2:

Add below permissions;

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />

Register for below intent;

private WifiBroadcastReceiver wifiBroadcastReceiver = new WifiBroadcastReceiver();

Then in routine;

registerReceiver(wifiBroadcastReceiver, new IntentFilter("android.net.wifi.SCAN_RESULTS"));

Use the below class to change the reassociation;

public class WifiBroadcastReceiver extends BroadcastReceiver {

    private WiFiManager manager = null;//set the value in constructor
    private WifiConfiguration connectedConfiguration = null;//set the value in constructor
    private int connectedNetId;

    private void updateConnectedConfiguration(String ssid) {
        configs = manager.getConfiguredNetworks();
        int nid = 0;
        for (WifiConfiguration cnf : configs) {
            if (cnf.SSID.substring(1, cnf.SSID.length() - 1).equals(ssid)) {
                connectedConfiguration = cnf;
                connectedNetId = nid;
            }
            nid++;
        }
    }


    public void onReceive(Context c, Intent intent) {
        List<ScanResult> results = manager.getScanResults();
        WifiInfo info = manager.getConnectionInfo();
        ScanResult stronger = null;
        for (ScanResult scanResult : results) {
            try {
                if (scanResult.SSID.equals(info.getSSID())) {
                    if (stronger == null) {
                        if (WifiManager.compareSignalLevel(info.getRssi() + 5, scanResult.level) < 0) {
                            stronger = scanResult;
                        }
                    } else if (WifiManager.compareSignalLevel(stronger.level, scanResult.level) < 0) {
                        stronger = scanResult;
                    }
                }
            } catch (Exception e) {
            }
        }
        if (stronger != null && !stronger.BSSID.equals(info.getBSSID())) {
            updateConnectedConfiguration(info.getSSID());
            if (connectedConfiguration != null) {
                connectedConfiguration.BSSID = stronger.BSSID;
                manager.updateNetwork(connectedConfiguration);
                manager.saveConfiguration();
                manager.enableNetwork(connectedNetId, true);
                manager.reassociate();
                info = manager.getConnectionInfo();
                //showNotification("\nConnecting " + stronger.SSID, stronger.BSSID + " " + stronger.level + "dBm");
            }
        }
    }
}