Wi-Fi ಮತ್ತು ಅನೇಕ ಇತರ ಸಂಕ್ಷೇಪಣಗಳು. ಊದಿಕೊಳ್ಳದೆಯೇ Android ಅಪ್ಲಿಕೇಶನ್‌ನಲ್ಲಿ Wi-Fi ನೋಡ್‌ಗಳ ಕುರಿತು ಡೇಟಾವನ್ನು ಹೇಗೆ ಪಡೆಯುವುದು

ಒಂದು ದಿನ ನಾನು Android ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಂದ Wi-Fi ನೆಟ್‌ವರ್ಕ್‌ಗಳನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡಬೇಕಾಗಿತ್ತು ಮತ್ತು ಪ್ರವೇಶ ಬಿಂದುಗಳ ಕುರಿತು ವಿವರವಾದ ಡೇಟಾವನ್ನು ಪಡೆಯಬೇಕಾಗಿತ್ತು.

ಇಲ್ಲಿ ನಾವು ಹಲವಾರು ತೊಂದರೆಗಳನ್ನು ಎದುರಿಸಬೇಕಾಯಿತು: ಆಫ್.ಆಂಡ್ರಾಯ್ಡ್ ದಸ್ತಾವೇಜನ್ನು ವಿವರಿಸಿದ ಹಲವು ವರ್ಗಗಳನ್ನು ಅಸಮ್ಮತಿಗೊಳಿಸಲಾಯಿತು (API ಮಟ್ಟ > 26), ಅದರಲ್ಲಿ ಪ್ರತಿಫಲಿಸಲಿಲ್ಲ; ದಾಖಲಾತಿಯಲ್ಲಿನ ಕೆಲವು ವಿಷಯಗಳ ವಿವರಣೆಯು ಕಡಿಮೆಯಾಗಿದೆ (ಉದಾಹರಣೆಗೆ, ವರ್ಗದ ಸಾಮರ್ಥ್ಯಗಳ ಕ್ಷೇತ್ರ ಸ್ಕ್ಯಾನ್ ಫಲಿತಾಂಶ ಬರೆಯುವ ಸಮಯದಲ್ಲಿ, ಬಹುತೇಕ ಏನನ್ನೂ ವಿವರಿಸಲಾಗಿಲ್ಲ, ಆದರೂ ಇದು ಬಹಳಷ್ಟು ಪ್ರಮುಖ ಡೇಟಾವನ್ನು ಒಳಗೊಂಡಿದೆ). ಮೂರನೆಯ ತೊಂದರೆಯು ನೀವು ಮೊದಲು Wi-Fi ಗೆ ಹತ್ತಿರವಾದಾಗ, ಸಿದ್ಧಾಂತವನ್ನು ಓದುವುದು ಮತ್ತು ಸ್ಥಳೀಯ ಹೋಸ್ಟ್ ಮೂಲಕ ರೂಟರ್ ಅನ್ನು ಹೊಂದಿಸುವುದನ್ನು ಹೊರತುಪಡಿಸಿ, ನೀವು ಪ್ರತ್ಯೇಕವಾಗಿ ಅರ್ಥವಾಗುವಂತಹ ಹಲವಾರು ಸಂಕ್ಷೇಪಣಗಳನ್ನು ಎದುರಿಸಬೇಕಾಗುತ್ತದೆ. ಆದರೆ ಅವುಗಳನ್ನು ಹೇಗೆ ಸಂಬಂಧಿಸುವುದು ಮತ್ತು ರಚಿಸುವುದು ಎಂಬುದು ಸ್ಪಷ್ಟವಾಗಿಲ್ಲದಿರಬಹುದು (ತೀರ್ಪು ವ್ಯಕ್ತಿನಿಷ್ಠವಾಗಿದೆ ಮತ್ತು ಹಿಂದಿನ ಅನುಭವವನ್ನು ಅವಲಂಬಿಸಿರುತ್ತದೆ).

NDK ಇಲ್ಲದೆ Android ಕೋಡ್‌ನಿಂದ Wi-Fi ಪರಿಸರದ ಕುರಿತು ಸಮಗ್ರ ಡೇಟಾವನ್ನು ಹೇಗೆ ಪಡೆಯುವುದು, ಭಿನ್ನತೆಗಳು, ಆದರೆ Android API ಅನ್ನು ಮಾತ್ರ ಬಳಸುವುದು ಮತ್ತು ಅದನ್ನು ಹೇಗೆ ಅರ್ಥೈಸಿಕೊಳ್ಳುವುದು ಎಂಬುದನ್ನು ಈ ಲೇಖನವು ಚರ್ಚಿಸುತ್ತದೆ.

ತಡ ಮಾಡದೆ ಕೋಡ್ ಬರೆಯಲು ಪ್ರಾರಂಭಿಸೋಣ.

1. ಯೋಜನೆಯನ್ನು ರಚಿಸಿ

ಈ ಟಿಪ್ಪಣಿಯನ್ನು ಒಂದಕ್ಕಿಂತ ಹೆಚ್ಚು ಬಾರಿ Android ಪ್ರಾಜೆಕ್ಟ್ ರಚಿಸಿದವರಿಗೆ ಉದ್ದೇಶಿಸಲಾಗಿದೆ, ಆದ್ದರಿಂದ ನಾವು ಈ ಐಟಂನ ವಿವರಗಳನ್ನು ಬಿಟ್ಟುಬಿಡುತ್ತೇವೆ. ಕೆಳಗಿನ ಕೋಡ್ ಅನ್ನು Kotlin ನಲ್ಲಿ ಪ್ರಸ್ತುತಪಡಿಸಲಾಗುತ್ತದೆ, minSdkVersion=23.

2. ಪ್ರವೇಶ ಅನುಮತಿಗಳು

ಅಪ್ಲಿಕೇಶನ್‌ನಿಂದ Wi-Fi ನೊಂದಿಗೆ ಕೆಲಸ ಮಾಡಲು, ನೀವು ಬಳಕೆದಾರರಿಂದ ಹಲವಾರು ಅನುಮತಿಗಳನ್ನು ಪಡೆಯಬೇಕಾಗುತ್ತದೆ. ಅನುಗುಣವಾಗಿ ದಸ್ತಾವೇಜನ್ನು, 8.0 ರ ನಂತರ OS ಆವೃತ್ತಿಗಳನ್ನು ಹೊಂದಿರುವ ಸಾಧನಗಳಲ್ಲಿ ನೆಟ್‌ವರ್ಕ್ ಅನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡಲು, ನೆಟ್‌ವರ್ಕ್ ಪರಿಸರದ ಸ್ಥಿತಿಯನ್ನು ವೀಕ್ಷಿಸಲು ಪ್ರವೇಶದ ಜೊತೆಗೆ, ಸಾಧನದ ವೈ-ಫೈ ಮಾಡ್ಯೂಲ್‌ನ ಸ್ಥಿತಿಯನ್ನು ಬದಲಾಯಿಸಲು ನಿಮಗೆ ಪ್ರವೇಶ ಬೇಕಾಗುತ್ತದೆ, ಅಥವಾ ನಿರ್ದೇಶಾಂಕಗಳಿಗೆ ಪ್ರವೇಶ (ಅಂದಾಜು ಅಥವಾ ನಿಖರವಾಗಿ). ಆವೃತ್ತಿ 9.0 ರಿಂದ ಪ್ರಾರಂಭಿಸಿ, ನೀವು ಎರಡಕ್ಕೂ ಬಳಕೆದಾರರನ್ನು ಪ್ರೇರೇಪಿಸಬೇಕು ಮತ್ತು ಸ್ಥಳ ಸೇವೆಗಳನ್ನು ಆನ್ ಮಾಡಲು ಬಳಕೆದಾರರನ್ನು ಸ್ಪಷ್ಟವಾಗಿ ವಿನಂತಿಸಬೇಕು. ಇದು Google ನ ಹುಚ್ಚಾಟವಾಗಿದೆ ಮತ್ತು ಅವನ ಮೇಲೆ ಕಣ್ಣಿಡಲು ನಮ್ಮ ಬಯಕೆಯಲ್ಲ ಎಂದು ಬಳಕೆದಾರರಿಗೆ ಧೈರ್ಯದಿಂದ ವಿವರಿಸಲು ಮರೆಯಬೇಡಿ :)

ಆದ್ದರಿಂದ, AndroidManifest.xml ನಲ್ಲಿ ನಾವು ಸೇರಿಸುತ್ತೇವೆ:

    <uses-permission android_name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android_name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android_name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android_name="android.permission.ACCESS_FINE_LOCATION"/>

ಮತ್ತು ಪ್ರಸ್ತುತ ಚಟುವಟಿಕೆಗೆ ಲಿಂಕ್ ಹೊಂದಿರುವ ಕೋಡ್‌ನಲ್ಲಿ:

import android.app.Activity
import android.content.Context
import android.location.LocationManager
import androidx.core.app.ActivityCompat

....

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            ActivityCompat.requestPermissions(
                activity,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.CHANGE_WIFI_STATE),
                1
            )
            makeEnableLocationServices(activity.applicationContext)
        } else {
            ActivityCompat.requestPermissions(
                activity,
                arrayOf(Manifest.permission.CHANGE_WIFI_STATE),
                1
            )
        }

    /* включает экран включения службы по определению местоположения */
    fun makeEnableLocationServices(context: Context) {
        // TODO: перед вызовом этой функции надо рассказать пользователю, зачем Вам доступ к местоположению
        val lm: LocationManager =
            context.applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager

        val gpsEnabled: Boolean = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
        val networkEnabled: Boolean = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

        if (!gpsEnabled && !networkEnabled) {
            context.startActivity(Intent(ACTION_LOCATION_SOURCE_SETTINGS));
        }
    }

3. ಬ್ರಾಡ್‌ಕಾಸ್ಟ್ ರಿಸೀವರ್ ಅನ್ನು ರಚಿಸಿ ಮತ್ತು ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್ ಪರಿಸರವನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡುವ ಕುರಿತು ಡೇಟಾ ಅಪ್‌ಡೇಟ್ ಈವೆಂಟ್‌ಗಳಿಗೆ ಚಂದಾದಾರರಾಗಿ

val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager

val wifiScanReceiver = object : BroadcastReceiver() {

  override fun onReceive(context: Context, intent: Intent) {
    val success = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)
    if (success) {
      scanSuccess()
    } 
  }
}

val intentFilter = IntentFilter()
/* подписываемся на сообщения о получении новых результатов сканирования */
intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)
context.registerReceiver(wifiScanReceiver, intentFilter)

val success = wifiManager.startScan()
if (!success) {
  /* что-то не получилось при запуске сканирования, проверьте выданые разрешения */
}

....

private fun scanSuccess() {
 /* вот они, результаты сканирования */
  val results: List<ScanResult> = wifiManager.scanResults
}

ದಸ್ತಾವೇಜನ್ನು WiFiManager.startScan ವಿಧಾನವನ್ನು API ಆವೃತ್ತಿ 28 ರಿಂದ ನಿರಾಕರಿಸಲಾಗಿದೆ ಎಂದು ಗುರುತಿಸಲಾಗಿದೆ, ಆದರೆ ಆಫ್ ಆಗಿದೆ. ಮಾರ್ಗದರ್ಶನ ಅದನ್ನು ಬಳಸಲು ಸೂಚಿಸುತ್ತದೆ.

ಒಟ್ಟಾರೆಯಾಗಿ, ನಾವು ವಸ್ತುಗಳ ಪಟ್ಟಿಯನ್ನು ಸ್ವೀಕರಿಸಿದ್ದೇವೆ ಸ್ಕ್ಯಾನ್ ಫಲಿತಾಂಶ.

4. ScanResult ಅನ್ನು ನೋಡಿ ಮತ್ತು ನಿಯಮಗಳನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳಿ

ಈ ವರ್ಗದ ಕೆಲವು ಕ್ಷೇತ್ರಗಳನ್ನು ನೋಡೋಣ ಮತ್ತು ಅವುಗಳ ಅರ್ಥವನ್ನು ವಿವರಿಸೋಣ:

ಎಸ್‌ಎಸ್‌ಐಡಿ - ಸೇವಾ ಸೆಟ್ ಐಡೆಂಟಿಫೈಯರ್ ಎನ್ನುವುದು ನೆಟ್‌ವರ್ಕ್‌ನ ಹೆಸರು

ಬಿಎಸ್ಎಸ್ಐಡಿ – ಮೂಲ ಸೇವಾ ಸೆಟ್ ಐಡೆಂಟಿಫೈಯರ್ – ನೆಟ್‌ವರ್ಕ್ ಅಡಾಪ್ಟರ್‌ನ MAC ವಿಳಾಸ (Wi-Fi ಪಾಯಿಂಟ್)

ಮಟ್ಟದ - ಸ್ವೀಕರಿಸಿದ ಸಿಗ್ನಲ್ ಸಾಮರ್ಥ್ಯ ಸೂಚಕ [dBm (ರಷ್ಯನ್ dBm) - ಡೆಸಿಬೆಲ್, ಉಲ್ಲೇಖ ಶಕ್ತಿ 1 mW.] - ಸ್ವೀಕರಿಸಿದ ಸಿಗ್ನಲ್ ಸಾಮರ್ಥ್ಯದ ಸೂಚಕ. 0 ರಿಂದ -100 ರವರೆಗಿನ ಮೌಲ್ಯವನ್ನು ತೆಗೆದುಕೊಳ್ಳುತ್ತದೆ, 0 ರಿಂದ ಮತ್ತಷ್ಟು, Wi-Fi ಪಾಯಿಂಟ್‌ನಿಂದ ನಿಮ್ಮ ಸಾಧನಕ್ಕೆ ಹೋಗುವ ಮಾರ್ಗದಲ್ಲಿ ಹೆಚ್ಚು ಸಿಗ್ನಲ್ ಪವರ್ ಕಳೆದುಹೋಗುತ್ತದೆ. ಹೆಚ್ಚಿನ ವಿವರಗಳನ್ನು ಕಾಣಬಹುದು, ಉದಾಹರಣೆಗೆ, ನಲ್ಲಿ ವಿಕಿಪೀಡಿಯ. ಇಲ್ಲಿ ನಾನು Android ವರ್ಗವನ್ನು ಬಳಸುವುದನ್ನು ಹೇಳುತ್ತೇನೆ ವೈಫೈ ಮ್ಯಾನೇಜರ್ ನೀವು ಆಯ್ಕೆ ಮಾಡುವ ಹಂತದಲ್ಲಿ ಸಿಗ್ನಲ್ ಮಟ್ಟವನ್ನು ಅತ್ಯುತ್ತಮದಿಂದ ಭಯಾನಕಕ್ಕೆ ಮಾಪನಾಂಕ ಮಾಡಬಹುದು:

        val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
        val numberOfLevels = 5
        val level = WifiManager.calculateSignalLevel(level, numberOfLevels)

ಆವರ್ತನ - Wi-Fi ಪಾಯಿಂಟ್ [Hz] ನ ಆಪರೇಟಿಂಗ್ ಆವರ್ತನ. ಆವರ್ತನದ ಜೊತೆಗೆ, ನೀವು ಕರೆಯಲ್ಪಡುವ ಚಾನಲ್ನಲ್ಲಿ ಆಸಕ್ತಿ ಹೊಂದಿರಬಹುದು. ಪ್ರತಿಯೊಂದು ಬಿಂದುವು ತನ್ನದೇ ಆದ ಕಾರ್ಯಾಚರಣೆಯ ಶುದ್ಧತೆಯನ್ನು ಹೊಂದಿದೆ. ಬರೆಯುವ ಸಮಯದಲ್ಲಿ, ವೈ-ಫೈ ಪಾಯಿಂಟ್‌ಗಳ ಅತ್ಯಂತ ಜನಪ್ರಿಯ ಶ್ರೇಣಿಯು 2.4 GHz ಆಗಿದೆ. ಆದರೆ, ಹೆಚ್ಚು ನಿಖರವಾಗಿ ಹೇಳಬೇಕೆಂದರೆ, ಪಾಯಿಂಟ್ ನಿಮ್ಮ ಫೋನ್‌ಗೆ ಹೆಸರಿಸಲಾದ ಆವರ್ತನಕ್ಕೆ ಸಮೀಪವಿರುವ ಸಂಖ್ಯೆಯ ಆವರ್ತನದಲ್ಲಿ ಮಾಹಿತಿಯನ್ನು ರವಾನಿಸುತ್ತದೆ. ಚಾನಲ್‌ಗಳ ಸಂಖ್ಯೆ ಮತ್ತು ಅನುಗುಣವಾದ ಆವರ್ತನಗಳು ಪ್ರಮಾಣೀಕರಿಸಲಾಗಿದೆ. ಹತ್ತಿರದ ಬಿಂದುಗಳು ವಿಭಿನ್ನ ಆವರ್ತನಗಳಲ್ಲಿ ಕಾರ್ಯನಿರ್ವಹಿಸುವಂತೆ ಇದನ್ನು ಮಾಡಲಾಗುತ್ತದೆ, ಇದರಿಂದಾಗಿ ಪರಸ್ಪರ ಹಸ್ತಕ್ಷೇಪ ಮಾಡುವುದಿಲ್ಲ ಮತ್ತು ಸಂವಹನದ ವೇಗ ಮತ್ತು ಗುಣಮಟ್ಟವನ್ನು ಪರಸ್ಪರ ಕಡಿಮೆ ಮಾಡುವುದಿಲ್ಲ. ಈ ಸಂದರ್ಭದಲ್ಲಿ, ಅಂಕಗಳು ಒಂದು ಆವರ್ತನದಲ್ಲಿ ಕಾರ್ಯನಿರ್ವಹಿಸುವುದಿಲ್ಲ, ಆದರೆ ಆವರ್ತನಗಳ ವ್ಯಾಪ್ತಿಯಲ್ಲಿ (ಪ್ಯಾರಾಮೀಟರ್ ಕಾಲುವೆ ಅಗಲ), ಚಾನಲ್ ಅಗಲ ಎಂದು ಕರೆಯಲಾಗುತ್ತದೆ. ಅಂದರೆ, ಪಕ್ಕದ (ಮತ್ತು ಪಕ್ಕದಲ್ಲಿ ಮಾತ್ರವಲ್ಲ, ತಮ್ಮಿಂದ 3) ಚಾನೆಲ್‌ಗಳಲ್ಲಿ ಕಾರ್ಯನಿರ್ವಹಿಸುವ ಬಿಂದುಗಳು ಪರಸ್ಪರ ಹಸ್ತಕ್ಷೇಪ ಮಾಡುತ್ತವೆ. ಈ ಸರಳ ಕೋಡ್ ನಿಮಗೆ ಉಪಯುಕ್ತವಾಗಬಹುದು, ಇದು 2.4 ಮತ್ತು 5 Ghz ಆವರ್ತನದೊಂದಿಗೆ ಬಿಂದುಗಳಿಗೆ ಆವರ್ತನ ಮೌಲ್ಯದಿಂದ ಚಾನಲ್ ಸಂಖ್ಯೆಯನ್ನು ಲೆಕ್ಕಾಚಾರ ಮಾಡಲು ನಿಮಗೆ ಅನುಮತಿಸುತ್ತದೆ:


    /* по частоте определяем номер канала */
    val channel: Int
        get() {
            return if (frequency in 2412..2484) {
                (frequency - 2412) / 5 + 1
            } else if (frequency in 5170..5825) {
                (frequency - 5170) / 5 + 34
            } else {
                -1
            }
        }

ಸಾಮರ್ಥ್ಯಗಳು - ವಿಶ್ಲೇಷಣೆಗಾಗಿ ಅತ್ಯಂತ ಆಸಕ್ತಿದಾಯಕ ಕ್ಷೇತ್ರ, ಅದರೊಂದಿಗೆ ಕೆಲಸ ಮಾಡಲು ಸಾಕಷ್ಟು ಸಮಯ ಬೇಕಾಗುತ್ತದೆ. ಇಲ್ಲಿ ಬಿಂದುವಿನ "ಸಾಮರ್ಥ್ಯಗಳನ್ನು" ಸಾಲಿನಲ್ಲಿ ಬರೆಯಲಾಗಿದೆ. ಈ ಸಂದರ್ಭದಲ್ಲಿ, ನೀವು ದಾಖಲಾತಿಯಲ್ಲಿ ಸ್ಟ್ರಿಂಗ್ ವ್ಯಾಖ್ಯಾನದ ವಿವರಗಳಿಗಾಗಿ ನೋಡಬೇಕಾಗಿಲ್ಲ. ಈ ಸಾಲಿನಲ್ಲಿ ಏನಾಗಬಹುದು ಎಂಬುದರ ಕೆಲವು ಉದಾಹರಣೆಗಳು ಇಲ್ಲಿವೆ:

[WPA-PSK-TKIP+CCMP][WPA2-PSK-TKIP+CCMP][WPS][ESS]
[WPA2-PSK-CCMP][ESS]
[WPA2-PSK-CCMP+TKIP][ESS]
[WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][ESS]
[ESS][WPS]

5. ಸಂಕ್ಷೇಪಣಗಳು ಮತ್ತು ಪಾರ್ಸಿಂಗ್ ಸಾಮರ್ಥ್ಯಗಳನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳುವುದು

android.net.wifi.* ಪ್ಯಾಕೇಜ್‌ನ ವರ್ಗಗಳನ್ನು ಲಿನಕ್ಸ್ ಉಪಯುಕ್ತತೆಯ ಅಡಿಯಲ್ಲಿ ಬಳಸಲಾಗಿದೆ ಎಂದು ನಮೂದಿಸುವುದು ಯೋಗ್ಯವಾಗಿದೆ. wpa_supplicant ಮತ್ತು ಸ್ಕ್ಯಾನ್ ಮಾಡುವಾಗ ಸಾಮರ್ಥ್ಯಗಳ ಕ್ಷೇತ್ರದಲ್ಲಿ ಔಟ್‌ಪುಟ್ ಫಲಿತಾಂಶವು ಫ್ಲ್ಯಾಗ್‌ಗಳ ಕ್ಷೇತ್ರದ ನಕಲು ಆಗಿದೆ.

ನಾವು ಸ್ಥಿರವಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತೇವೆ. ಆವರಣದೊಳಗಿನ ಅಂಶಗಳನ್ನು "-" ಚಿಹ್ನೆಯಿಂದ ಬೇರ್ಪಡಿಸುವ ಸ್ವರೂಪದ ಔಟ್‌ಪುಟ್ ಅನ್ನು ಮೊದಲು ಪರಿಗಣಿಸೋಣ:

[WPA-PSK-TKIP+CCMP]
[WPA2-PSK-CCMP]

ಮೊದಲ ಅರ್ಥವು ಕರೆಯಲ್ಪಡುವದನ್ನು ವಿವರಿಸುತ್ತದೆ. ದೃಢೀಕರಣ ವಿಧಾನ. ಅಂದರೆ, ಪ್ರವೇಶ ಬಿಂದುವನ್ನು ಬಳಸಲು ಅನುಮತಿಸಲು ಸಾಧನ ಮತ್ತು ಪ್ರವೇಶ ಬಿಂದುವು ಯಾವ ಕ್ರಮಗಳ ಅನುಕ್ರಮವನ್ನು ನಿರ್ವಹಿಸಬೇಕು ಮತ್ತು ಪೇಲೋಡ್ ಅನ್ನು ಎನ್‌ಕ್ರಿಪ್ಟ್ ಮಾಡುವುದು ಹೇಗೆ. ಈ ಪೋಸ್ಟ್ ಅನ್ನು ಬರೆಯುವ ಸಮಯದಲ್ಲಿ, ಅತ್ಯಂತ ಸಾಮಾನ್ಯವಾದ ಆಯ್ಕೆಗಳು WPA ಮತ್ತು WPA2, ಇದರಲ್ಲಿ ಪ್ರತಿಯೊಂದು ಸಂಪರ್ಕಿತ ಸಾಧನವನ್ನು ನೇರವಾಗಿ ಅಥವಾ ಕರೆಯಲ್ಪಡುವ ಮೂಲಕ. RADIUS ಸರ್ವರ್ (WPA-ಎಂಟರ್‌ಪ್ರೈಸ್) ಎನ್‌ಕ್ರಿಪ್ಟ್ ಮಾಡಿದ ಚಾನಲ್‌ನಲ್ಲಿ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ಒದಗಿಸುತ್ತದೆ. ಹೆಚ್ಚಾಗಿ, ನಿಮ್ಮ ಮನೆಯ ಪ್ರವೇಶ ಬಿಂದುವು ಈ ಯೋಜನೆಯ ಪ್ರಕಾರ ಸಂಪರ್ಕವನ್ನು ಒದಗಿಸುತ್ತದೆ. ಎರಡನೆಯ ಮತ್ತು ಮೊದಲನೆಯ ಆವೃತ್ತಿಯ ನಡುವಿನ ವ್ಯತ್ಯಾಸವೆಂದರೆ ಅದು ಬಲವಾದ ಸೈಫರ್ ಅನ್ನು ಹೊಂದಿದೆ: AES ವಿರುದ್ಧ ಅಸುರಕ್ಷಿತ TKIP. ಹೆಚ್ಚು ಸಂಕೀರ್ಣ ಮತ್ತು ಮುಂದುವರಿದ WPA3 ಅನ್ನು ಸಹ ಕ್ರಮೇಣ ಪರಿಚಯಿಸಲಾಗುತ್ತಿದೆ. ಸೈದ್ಧಾಂತಿಕವಾಗಿ, ಎಂಟರ್‌ಪ್ರೈಸ್ ಪರಿಹಾರ CCKM (ಸಿಸ್ಕೊ ​​ಸೆಂಟ್ರಲೈಸ್ಡ್ ಕೀ ಮ್ಯಾನೇಜ್‌ಮೆಂಟ್) ನೊಂದಿಗೆ ಒಂದು ಆಯ್ಕೆ ಇರಬಹುದು, ಆದರೆ ನಾನು ಅದನ್ನು ಎಂದಿಗೂ ನೋಡಿಲ್ಲ.

ಪ್ರವೇಶ ಬಿಂದುವನ್ನು MAC ವಿಳಾಸದಿಂದ ದೃಢೀಕರಿಸಲು ಕಾನ್ಫಿಗರ್ ಮಾಡಿರಬಹುದು. ಅಥವಾ, ಪ್ರವೇಶ ಬಿಂದುವು ಹಳತಾದ WEP ಅಲ್ಗಾರಿದಮ್ ಅನ್ನು ಬಳಸಿಕೊಂಡು ಡೇಟಾವನ್ನು ಒದಗಿಸಿದರೆ, ವಾಸ್ತವವಾಗಿ ಯಾವುದೇ ದೃಢೀಕರಣವಿಲ್ಲ (ಇಲ್ಲಿ ರಹಸ್ಯ ಕೀಲಿಯು ಎನ್‌ಕ್ರಿಪ್ಶನ್ ಕೀ ಆಗಿದೆ). ನಾವು ಅಂತಹ ಆಯ್ಕೆಗಳನ್ನು OTHER ಎಂದು ವರ್ಗೀಕರಿಸುತ್ತೇವೆ.
ಗುಪ್ತ ಕ್ಯಾಪ್ಟಿವ್ ಪೋರ್ಟಲ್ ಡಿಟೆಕ್ಷನ್‌ನೊಂದಿಗೆ ಸಾರ್ವಜನಿಕ ವೈ-ಫೈನಲ್ಲಿ ಜನಪ್ರಿಯವಾಗಿರುವ ಒಂದು ವಿಧಾನವೂ ಇದೆ - ಬ್ರೌಸರ್ ಮೂಲಕ ದೃಢೀಕರಣ ವಿನಂತಿ. ಅಂತಹ ಪ್ರವೇಶ ಬಿಂದುಗಳು ಸ್ಕ್ಯಾನರ್‌ಗೆ ತೆರೆದಂತೆ ಗೋಚರಿಸುತ್ತವೆ (ಅವು ಭೌತಿಕ ಸಂಪರ್ಕದ ದೃಷ್ಟಿಕೋನದಿಂದ). ಆದ್ದರಿಂದ, ನಾವು ಅವುಗಳನ್ನು OPEN ಎಂದು ವರ್ಗೀಕರಿಸುತ್ತೇವೆ.

ಎರಡನೇ ಮೌಲ್ಯವನ್ನು ಹೀಗೆ ಸೂಚಿಸಬಹುದು ಪ್ರಮುಖ ನಿರ್ವಹಣಾ ಅಲ್ಗಾರಿದಮ್. ಇದು ಮೇಲೆ ವಿವರಿಸಿದ ದೃಢೀಕರಣ ವಿಧಾನದ ನಿಯತಾಂಕವಾಗಿದೆ. ಗೂಢಲಿಪೀಕರಣ ಕೀಗಳನ್ನು ನಿಖರವಾಗಿ ಹೇಗೆ ವಿನಿಮಯ ಮಾಡಿಕೊಳ್ಳಲಾಗುತ್ತದೆ ಎಂಬುದರ ಕುರಿತು ಮಾತನಾಡುತ್ತಾರೆ. ಸಂಭವನೀಯ ಆಯ್ಕೆಗಳನ್ನು ಪರಿಗಣಿಸೋಣ. EAP - ನಮೂದಿಸಲಾದ WPA-ಎಂಟರ್‌ಪ್ರೈಸ್‌ನಲ್ಲಿ ಬಳಸಲಾಗಿದೆ, ನಮೂದಿಸಿದ ದೃಢೀಕರಣ ಡೇಟಾವನ್ನು ಪರಿಶೀಲಿಸಲು ಡೇಟಾಬೇಸ್ ಅನ್ನು ಬಳಸುತ್ತದೆ. SAE - ಸುಧಾರಿತ WPA3 ನಲ್ಲಿ ಬಳಸಲಾಗುತ್ತದೆ, ವಿವೇಚನಾರಹಿತ ಶಕ್ತಿಗೆ ಹೆಚ್ಚು ನಿರೋಧಕವಾಗಿದೆ. PSK - ಅತ್ಯಂತ ಸಾಮಾನ್ಯವಾದ ಆಯ್ಕೆ, ಪಾಸ್ವರ್ಡ್ ಅನ್ನು ನಮೂದಿಸುವುದನ್ನು ಮತ್ತು ಅದನ್ನು ಎನ್ಕ್ರಿಪ್ಟ್ ಮಾಡಿದ ರೂಪದಲ್ಲಿ ರವಾನಿಸುವುದನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ. IEEE8021X - ಅಂತರಾಷ್ಟ್ರೀಯ ಮಾನದಂಡದ ಪ್ರಕಾರ (WPA ಕುಟುಂಬದಿಂದ ಬೆಂಬಲಿತವಾಗಿದೆ). OWE (ಅವಕಾಶವಾದಿ ವೈರ್‌ಲೆಸ್ ಎನ್‌ಕ್ರಿಪ್ಶನ್) ನಾವು OPEN ಎಂದು ವರ್ಗೀಕರಿಸಿದ ಪಾಯಿಂಟ್‌ಗಳಿಗಾಗಿ IEEE 802.11 ಮಾನದಂಡದ ವಿಸ್ತರಣೆಯಾಗಿದೆ. ಎನ್‌ಕ್ರಿಪ್ಟ್ ಮಾಡುವ ಮೂಲಕ ಅಸುರಕ್ಷಿತ ನೆಟ್‌ವರ್ಕ್ ಮೂಲಕ ರವಾನೆಯಾಗುವ ಡೇಟಾದ ಸುರಕ್ಷತೆಯನ್ನು OWE ಖಚಿತಪಡಿಸುತ್ತದೆ. ಯಾವುದೇ ಪ್ರವೇಶ ಕೀಗಳು ಇಲ್ಲದಿರುವಾಗ ಒಂದು ಆಯ್ಕೆಯೂ ಸಾಧ್ಯ, ಈ ಆಯ್ಕೆಯನ್ನು NONE ಎಂದು ಕರೆಯೋಣ.

ಮೂರನೆಯ ನಿಯತಾಂಕವು ಕರೆಯಲ್ಪಡುವದು. ಗೂಢಲಿಪೀಕರಣ ಯೋಜನೆಗಳು — ರವಾನೆಯಾದ ಡೇಟಾವನ್ನು ರಕ್ಷಿಸಲು ಸೈಫರ್ ಅನ್ನು ಎಷ್ಟು ನಿಖರವಾಗಿ ಬಳಸಲಾಗುತ್ತದೆ. ಆಯ್ಕೆಗಳನ್ನು ಪಟ್ಟಿ ಮಾಡೋಣ. WEP - RC4 ಸ್ಟ್ರೀಮ್ ಸೈಫರ್ ಅನ್ನು ಬಳಸುತ್ತದೆ, ರಹಸ್ಯ ಕೀಲಿಯು ಎನ್‌ಕ್ರಿಪ್ಶನ್ ಕೀ ಆಗಿದೆ, ಇದನ್ನು ಆಧುನಿಕ ಕ್ರಿಪ್ಟೋಗ್ರಫಿ ಜಗತ್ತಿನಲ್ಲಿ ಸ್ವೀಕಾರಾರ್ಹವಲ್ಲ ಎಂದು ಪರಿಗಣಿಸಲಾಗಿದೆ. TKIP - WPA ನಲ್ಲಿ ಬಳಸಲಾಗುತ್ತದೆ, CKIP - WPA2 ನಲ್ಲಿ. TKIP+CKIP - ಹಿಂದುಳಿದ ಹೊಂದಾಣಿಕೆಗಾಗಿ WPA ಮತ್ತು WPA2 ಸಾಮರ್ಥ್ಯವಿರುವ ಬಿಂದುಗಳಲ್ಲಿ ನಿರ್ದಿಷ್ಟಪಡಿಸಬಹುದು.

ಮೂರು ಅಂಶಗಳ ಬದಲಿಗೆ, ನೀವು ಲೋನ್ಲಿ WEP ಮಾರ್ಕ್ ಅನ್ನು ಕಾಣಬಹುದು:

[WEP]

ನಾವು ಮೇಲೆ ಚರ್ಚಿಸಿದಂತೆ, ಅಸ್ತಿತ್ವದಲ್ಲಿಲ್ಲದ ಕೀಗಳನ್ನು ಬಳಸುವ ಅಲ್ಗಾರಿದಮ್ ಮತ್ತು ಪೂರ್ವನಿಯೋಜಿತವಾಗಿ ಒಂದೇ ಆಗಿರುವ ಎನ್‌ಕ್ರಿಪ್ಶನ್ ವಿಧಾನವನ್ನು ನಿರ್ದಿಷ್ಟಪಡಿಸದಿರಲು ಇದು ಸಾಕಾಗುತ್ತದೆ.

ಈಗ ಈ ಬ್ರಾಕೆಟ್ ಅನ್ನು ಪರಿಗಣಿಸಿ:

[ESS]

Wi-Fi ಆಪರೇಟಿಂಗ್ ಮೋಡ್ ಅಥವಾ Wi-Fi ನೆಟ್ವರ್ಕ್ ಟೋಪೋಲಜಿ. ನೀವು BSS (ಮೂಲ ಸೇವಾ ಸೆಟ್) ಮೋಡ್ ಅನ್ನು ಎದುರಿಸಬಹುದು - ಸಂಪರ್ಕಿತ ಸಾಧನಗಳು ಸಂವಹನ ಮಾಡುವ ಒಂದು ಪ್ರವೇಶ ಬಿಂದುವಿದ್ದಾಗ. ಸ್ಥಳೀಯ ನೆಟ್ವರ್ಕ್ಗಳಲ್ಲಿ ಕಾಣಬಹುದು. ನಿಯಮದಂತೆ, ವಿವಿಧ ಸ್ಥಳೀಯ ನೆಟ್‌ವರ್ಕ್‌ಗಳಿಂದ ಸಾಧನಗಳನ್ನು ಸಂಪರ್ಕಿಸಲು ಪ್ರವೇಶ ಬಿಂದುಗಳು ಅಗತ್ಯವಿದೆ, ಆದ್ದರಿಂದ ಅವು ವಿಸ್ತೃತ ಸೇವಾ ಸೆಟ್‌ಗಳ ಭಾಗವಾಗಿದೆ - ESS. IBSSs (ಸ್ವತಂತ್ರ ಮೂಲ ಸೇವಾ ಸೆಟ್‌ಗಳು) ಪ್ರಕಾರವು ಸಾಧನವು ಪೀರ್-ಟು-ಪೀರ್ ನೆಟ್‌ವರ್ಕ್‌ನ ಭಾಗವಾಗಿದೆ ಎಂದು ಸೂಚಿಸುತ್ತದೆ.

ನೀವು WPS ಧ್ವಜವನ್ನು ಸಹ ನೋಡಬಹುದು:

[WPS]

WPS (Wi-Fi ರಕ್ಷಿತ ಸೆಟಪ್) Wi-Fi ನೆಟ್ವರ್ಕ್ನ ಅರೆ-ಸ್ವಯಂಚಾಲಿತ ಪ್ರಾರಂಭಕ್ಕಾಗಿ ಪ್ರೋಟೋಕಾಲ್ ಆಗಿದೆ. ಪ್ರಾರಂಭಿಸಲು, ಬಳಕೆದಾರರು 8-ಅಕ್ಷರಗಳ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ನಮೂದಿಸುತ್ತಾರೆ ಅಥವಾ ರೂಟರ್‌ನಲ್ಲಿ ಬಟನ್ ಅನ್ನು ಒತ್ತುತ್ತಾರೆ. ನಿಮ್ಮ ಪ್ರವೇಶ ಬಿಂದುವು ಮೊದಲ ಪ್ರಕಾರವಾಗಿದ್ದರೆ ಮತ್ತು ನಿಮ್ಮ ಪ್ರವೇಶ ಬಿಂದುವಿನ ಹೆಸರಿನ ಮುಂದೆ ಈ ಚೆಕ್‌ಬಾಕ್ಸ್ ಗೋಚರಿಸಿದರೆ, ನಿರ್ವಾಹಕ ಫಲಕಕ್ಕೆ ಹೋಗಿ ಮತ್ತು WPS ಪ್ರವೇಶವನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ನಿಮ್ಮನ್ನು ಬಲವಾಗಿ ಶಿಫಾರಸು ಮಾಡಲಾಗಿದೆ. ಸತ್ಯವೆಂದರೆ ಸಾಮಾನ್ಯವಾಗಿ 8-ಅಂಕಿಯ ಪಿನ್ ಅನ್ನು MAC ವಿಳಾಸದಿಂದ ಕಂಡುಹಿಡಿಯಬಹುದು ಅಥವಾ ಅದನ್ನು ನಿರೀಕ್ಷಿತ ಸಮಯದಲ್ಲಿ ವಿಂಗಡಿಸಬಹುದು, ಅದನ್ನು ಯಾರಾದರೂ ಅಪ್ರಾಮಾಣಿಕವಾಗಿ ಲಾಭ ಪಡೆಯಬಹುದು.

6. ಮಾದರಿ ಮತ್ತು ಪಾರ್ಸಿಂಗ್ ಕಾರ್ಯವನ್ನು ರಚಿಸಿ

ನಾವು ಮೇಲೆ ಕಂಡುಕೊಂಡದ್ದನ್ನು ಆಧರಿಸಿ, ಡೇಟಾ ತರಗತಿಗಳನ್ನು ಬಳಸಿಕೊಂಡು ಏನಾಯಿತು ಎಂಬುದನ್ನು ನಾವು ವಿವರಿಸುತ್ತೇವೆ:

/* схема аутентификации */
enum class AuthMethod {
    WPA3,
    WPA2,
    WPA, // Wi-Fi Protected Access
    OTHER, // включает в себя Shared Key Authentication и др. использующие mac-address-based и WEP
    CCKM, // Cisco
    OPEN // Open Authentication. Может быть со скрытым Captive Portal Detection - запрос аутентификации через браузер
}

/* алгоритм ввода ключей */
enum class KeyManagementAlgorithm {
    IEEE8021X, // по стандарту
    EAP, // Extensible Authentication Protocol, расширяемый протокол аутентификации
    PSK, // Pre-Shared Key — каждый узел вводит пароль для доступа к сети
    WEP, // в WEP пароль является ключом шифрования (No auth key)
    SAE, // Simultaneous Authentication of Equals - может быть в WPA3
    OWE, // Opportunistic Wireless Encryption - в роутерах новых поколений, публичных сетях типа OPEN
    NONE // может быть без шифрования в OPEN, OTHER
}

/* метод шифрования */
enum class CipherMethod {
    WEP, // Wired Equivalent Privacy, Аналог шифрования трафика в проводных сетях
    TKIP, // Temporal Key Integrity Protocol
    CCMP, // Counter Mode with Cipher Block Chaining Message Authentication Code Protocol,
    // протокол блочного шифрования с кодом аутентичности сообщения и режимом сцепления блоков и счетчика
    // на основе AES
    NONE // может быть без шифрования в OPEN, OTHER
}

/* набор методов шифрования и протоколов, по которым может работать точка */
data class Capability(
    var authScheme: AuthMethod? = null,
    var keyManagementAlgorithm: KeyManagementAlgorithm? = null,
    var cipherMethod: CipherMethod? = null
)

/* Режим работы WiFi (или топология сетей WiFi) */
enum class TopologyMode {
    IBSS, // Эпизодическая сеть (Ad-Hoc или IBSS – Independent Basic Service Set).
    BSS, // Основная зона обслуживания Basic Service Set (BSS) или Infrastructure Mode.
    ESS // Расширенная зона обслуживания ESS – Extended Service Set.
}

ಈಗ ಸಾಮರ್ಥ್ಯಗಳ ಕ್ಷೇತ್ರವನ್ನು ಪಾರ್ಸ್ ಮಾಡುವ ಕಾರ್ಯವನ್ನು ಬರೆಯೋಣ:


private fun parseCapabilities(capabilitiesString: String): List < Capability > {
    val capabilities: List < Capability > = capabilitiesString
        .splitByBrackets()
        .filter {
            !it.isTopology() && !it.isWps()
        }
        .flatMap {
            parseCapability(it)
        }
    return
        if (!capabilities.isEmpty()) {
            capabilities
        } else {
            listOf(Capability(AuthMethod.OPEN, KeyManagementAlgorithm.NONE, CipherMethod.NONE))
        }
}

private fun parseCapability(part: String): List < Capability > {
    if (part.contains("WEP")) {
        return listOf(Capability(
            AuthMethod.OTHER,
            KeyManagementAlgorithm.WEP,
            CipherMethod.WEP
        ))
    }

    val authScheme = when {
        part.contains("WPA3") - > AuthMethod.WPA3
        part.contains("WPA2") - > AuthMethod.WPA2
        part.contains("WPA") - > AuthMethod.WPA
        else - > null
    }

    val keyManagementAlgorithm = when {
        part.contains("OWE") - > KeyManagementAlgorithm.OWE
        part.contains("SAE") - > KeyManagementAlgorithm.SAE
        part.contains("IEEE802.1X") - > KeyManagementAlgorithm.IEEE8021X
        part.contains("EAP") - > KeyManagementAlgorithm.EAP
        part.contains("PSK") - > KeyManagementAlgorithm.PSK
        else - > null
    }

    val capabilities = ArrayList < Capability > ()
    if (part.contains("TKIP") || part.contains("CCMP")) {
        if (part.contains("TKIP")) {
            capabilities.add(Capability(
                authScheme ? : AuthMethod.OPEN,
                keyManagementAlgorithm ? : KeyManagementAlgorithm.NONE,
                CipherMethod.TKIP
            ))
        }
        if (part.contains("CCMP")) {
            capabilities.add(Capability(
                authScheme ? : AuthMethod.OPEN,
                keyManagementAlgorithm ? : KeyManagementAlgorithm.NONE,
                CipherMethod.CCMP
            ))
        }
    } else if (authScheme != null || keyManagementAlgorithm != null) {
        capabilities.add(Capability(
            authScheme ? : AuthMethod.OPEN,
            keyManagementAlgorithm ? : KeyManagementAlgorithm.NONE,
            CipherMethod.NONE
        ))
    }

    return capabilities
}

private fun parseTopologyMode(capabilitiesString: String): TopologyMode ? {
    return capabilitiesString
        .splitByBrackets()
        .mapNotNull {
            when {
                it.contains("ESS") - > TopologyMode.ESS
                it.contains("BSS") - > TopologyMode.BSS
                it.contains("IBSS") - > TopologyMode.IBSS
                else - > null
            }
        }
        .firstOrNull()
}

private fun parseWPSAvailable(capabilitiesString: String): Boolean {
    return capabilitiesString
        .splitByBrackets()
        .any {
            it.isWps()
        }
}

private fun String.splitByBrackets(): List < String > {
    val m = Pattern.compile("[(.*?)]").matcher(this)
    val parts = ArrayList < String > ()
    while (m.find()) {
        parts.add(m.group().replace("[", "").replace("]", ""))
    }
    return parts
}

private fun String.isTopology(): Boolean {
    return TopologyMode.values().any {
        this == it.name
    }
}

private fun String.isWps(): Boolean {
    return this == "WPS"
}

8. ಫಲಿತಾಂಶವನ್ನು ನೋಡಿ

ನಾನು ನೆಟ್‌ವರ್ಕ್ ಅನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡುತ್ತೇನೆ ಮತ್ತು ನಾನು ಕಂಡುಕೊಂಡದ್ದನ್ನು ನಿಮಗೆ ತೋರಿಸುತ್ತೇನೆ. Log.d ಮೂಲಕ ಸರಳ ಔಟ್‌ಪುಟ್‌ನ ಫಲಿತಾಂಶಗಳನ್ನು ತೋರಿಸಲಾಗಿದೆ:

Capability of Home-Home [WPA2-PSK-CCMP][ESS][WPS]
...
capabilities=[Capability(authScheme=WPA2, keyManagementAlgorithm=PSK, cipherMethod=CCMP)], topologyMode=ESS, availableWps=true

ಅಪ್ಲಿಕೇಶನ್ ಕೋಡ್‌ನಿಂದ ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸಂಪರ್ಕಿಸುವ ಸಮಸ್ಯೆಯನ್ನು ಪರಿಶೀಲಿಸಲಾಗಿಲ್ಲ. ಮೊಬೈಲ್ ಸಾಧನದ OS ನಿಂದ ಉಳಿಸಿದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು ಓದಲು, ನಿಮಗೆ ರೂಟ್ ಹಕ್ಕುಗಳು ಮತ್ತು wpa_supplicant.conf ಅನ್ನು ಓದಲು ಫೈಲ್ ಸಿಸ್ಟಮ್ ಮೂಲಕ ಗುಜರಿ ಮಾಡುವ ಇಚ್ಛೆಯ ಅಗತ್ಯವಿದೆ ಎಂದು ನಾನು ಹೇಳುತ್ತೇನೆ. ಅಪ್ಲಿಕೇಶನ್ ತರ್ಕಕ್ಕೆ ಹೊರಗಿನಿಂದ ಪಾಸ್‌ವರ್ಡ್ ನಮೂದಿಸುವ ಅಗತ್ಯವಿದ್ದರೆ, ಸಂಪರ್ಕವನ್ನು ವರ್ಗದ ಮೂಲಕ ಮಾಡಬಹುದು android.net.wifi.WifiManager.

ಸಪಾಕ್ಸಿ ಎಗೊರ್ ಪೊನೊಮರೆವ್ ಮೌಲ್ಯಯುತ ಸೇರ್ಪಡೆಗಳಿಗಾಗಿ.

ಏನನ್ನಾದರೂ ಸೇರಿಸಬೇಕು ಅಥವಾ ಸರಿಪಡಿಸಬೇಕು ಎಂದು ನೀವು ಭಾವಿಸಿದರೆ, ಕಾಮೆಂಟ್‌ಗಳಲ್ಲಿ ಬರೆಯಿರಿ :)

ಮೂಲ: www.habr.com

ಕಾಮೆಂಟ್ ಅನ್ನು ಸೇರಿಸಿ