Android 网络链接稳定性测试解决方案

简介: Android 网络链接稳定性测试解决方案

Android开发中,我们经常需要通过网络请求来获取数据或执行某些操作。但是,网络连接并不总是稳定的,有时候会出现延迟、丢包、断开等问题,这些问题会影响用户的体验和满意度。因此,我们需要对网络连接的稳定性进行测试,找出可能存在的问题,并采取相应的优化措施。

为了测试Android应用在不同网络环境下的表现,我们可以使用一些工具或方法来模拟网络的变化,比如使用[Network Link Conditioner]或[Android Emulator]等。但是,这些工具或方法都有一些局限性,比如不能覆盖所有的网络类型和场景,或者不能实时反映网络状态的变化。

因此,需要一种更灵活和全面的解决方案,来测试Android应用在真实网络环境下的稳定性。本文将介绍一种基于后台服务和定时器的解决方案,它可以在后台持续地发送HTTP请求到一些可靠的服务器,并记录响应的时间和状态码,从而评估网络连接的稳定性。同时,它还可以将测试结果保存到本地文件,并定期上传到远程服务器,方便我们进行分析和比较。

我开始本来想使用tomcat搭建的,但后来发现缺少后台,后面就考虑用scp技术,直接把结果push到服务器。

目标

目标是设计一个Android网络连接稳定性测试解决方案,具体要求如下:

  • 可以对不同类型的网络(如WIFI、4G、以太网等)进行测试
  • 可以对不同的服务器(如百度、必硬等)进行测试
  • 可以记录每次请求的时间、状态码、时间戳等信息
  • 可以将测试结果保存到本地文件,并定期上传到远程服务器
  • 可以统计测试结果的总次数、成功次数、失败次数、成功率等指标

实现

为了实现这个目标,需要使用以下几个组件:

  • NetworkMonitorService:一个后台服务,用来发送HTTP请求,并记录响应的时间和状态码
  • FileUploadService:一个后台服务,用来将测试结果保存到本地文件,并上传到远程服务器
  • NetworkMonitorReceiver:一个广播接收器,用来启动NetworkMonitorService
  • FileUploadReceiver:一个广播接收器,用来启动FileUploadService
  • DatabaseHelper:一个数据库操作类,用来插入和查询测试结果
  • NetworkHelper:一个网络操作类,用来获取当前的网络类型和IP地址

下面我们分别介绍这些组件的具体实现。

NetworkMonitorService

NetworkMonitorService是一个继承自JobIntentService的后台服务,它可以在后台线程上处理传入的工作请求。重写了它的onHandleWork方法,在这个方法中,做了以下几件事:

  • 获取一个OkHttpClient实例,用来发送HTTP请求
  • 获取一个DatabaseHelper实例,用来操作本地数据库
  • 获取当前的网络类型和IP地址
  • 遍历可靠的服务器的URL,依次发送HTTP请求,并记录响应的时间和状态码
  • 插入一条数据到数据库,并检查数据量

代码如下:

package com.xxx.factorytest.service;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.core.app.JobIntentService;
import com.xxx.factorytest.utils.DatabaseHelper;
import com.xxx.factorytest.utils.NetworkHelper;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class NetworkMonitorService extends JobIntentService {
    // 定义一个工作ID,用来唯一标识这个服务
    private static final int JOB_ID = 1;
    // 定义最大的数据量
    private static final int MAX_DATA_COUNT = 1000;
    // 定义一些可靠的服务器的URL,用来发送HTTP请求
    private static final String[] SERVER_URLS = {
            "https://www.baidu.com",
    };
    // 定义一个静态方法,用来启动这个服务
    public static void startService(Context context) {
        Log.d("NetworkMonitorService", "startService");
        Intent intent = new Intent(context, NetworkMonitorService.class);
        enqueueWork(context, NetworkMonitorService.class, JOB_ID, intent);
    }
    // 重写onHandleWork方法,在后台线程上处理传入的工作请求
    @Override
    protected void onHandleWork(@NonNull Intent intent) {
        Log.d("NetworkMonitorService", "onHandleWork");
        // 获取一个OkHttpClient实例,用来发送HTTP请求
        OkHttpClient client = new OkHttpClient();
        // 获取一个DatabaseHelper实例,用来操作本地数据库
        DatabaseHelper databaseHelper = new DatabaseHelper(this);
        // 获取当前的网络类型和IP地址
        String networkType = NetworkHelper.getCurrentNetworkType(getApplicationContext());
        String ipAddress = NetworkHelper.getCurrentIpAddress(getApplicationContext());
        // 遍历可靠的服务器的URL,依次发送HTTP请求,并记录响应的时间和状态码
        for (String url : SERVER_URLS) {
            // 创建一个Request对象,用来封装HTTP请求
            Request request = new Request.Builder()
                    .url(url)
                    .build();
            // 发送异步HTTP请求,并注册一个回调函数
            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(@NonNull Call call, @NonNull IOException e) {
                    // 获取当前时间戳
                    long timestamp = System.currentTimeMillis();
                    // 插入一条数据,并检查数据量,时间设置为-1,状态码设置为-1,表示请求失败
                    databaseHelper.insertData(url, -1, -1, timestamp, networkType + "_" + ipAddress);
                }
                @Override
                public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                    // 处理正常情况,获取响应的时间和状态码
                    // 计算请求花费的时间,单位为毫秒
                    long time = response.receivedResponseAtMillis() - response.sentRequestAtMillis();
                    // 获取响应的状态码
                    int status = response.code();
                    // 获取当前时间戳
                    long timestamp = System.currentTimeMillis();
                    // 打印日志,显示请求的URL,时间和状态码
                    Log.d("NetworkMonitorService", "URL: " + url + ", Time: " + time + " ms, Status: " + status);
                    // 插入一条数据,并检查数据量
                    databaseHelper.insertData(url, time, status, timestamp, networkType + "_" + ipAddress);
                }
            });
        }
    }
}

FileUploadService

FileUploadService也是一个继承自JobIntentService的后台服务,它可以在后台线程上处理传入的工作请求。我们重写了它的onHandleWork方法,在这个方法中,我们做了以下几件事:

  • 将测试结果从数据库中读取出来,并写入到本地文件中
  • 使用JSch库,通过SSH协议,将本地文件上传到远程服务器上

代码如下:

package com.xxx.factorytest.service;
import android.btf.VendorStorageManager;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Environment;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.core.app.JobIntentService;
import com.xxx.factorytest.utils.DatabaseHelper;
import com.xxx.factorytest.utils.NetworkHelper;
import com.xxx.factorytest.utils.Utils;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class FileUploadService extends JobIntentService {
    public static final String LOCAL_FILE_PATH = Environment.getExternalStorageDirectory() + "/"+ getCurrentSystemTime() +"_"+ getCPUSerial()+ ".log";
    private static final int JOB_ID = 2;
    private static final String TAG = "FileUploadService";
    public static void startService(Context context) {
        Intent intent = new Intent(context, FileUploadService.class);
        enqueueWork(context, FileUploadService.class, JOB_ID, intent);
    }
    @Override
    protected void onHandleWork(@NonNull Intent intent) {
        writeDataToFile();
        uploadFile("username", "123456", "192.168.1.22", 22, LOCAL_FILE_PATH, "/home/work2/network_test/");
    }
    // 获取当前系统时间的函数
    private static String getCurrentSystemTime() {
        // 创建一个SimpleDateFormat对象,指定日期格式为yyyyMMdd
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
        // 获取当前日期对象
        Date date = new Date(System.currentTimeMillis());
        // 格式化日期对象,返回字符串
        return simpleDateFormat.format(date);
    }
    private void uploadFile(String username, String password, String host, int port, String localFile, String remoteDir) {
        JSch jsch = new JSch();
        Session session = null;
        try {
            session = jsch.getSession(username, host, port);
            session.setPassword(password);
            session.setConfig("StrictHostKeyChecking", "no");
            session.connect();
            Log.d(TAG, "Connected to SSH server");
            ChannelSftp sftp = (ChannelSftp) session.openChannel("sftp");
            sftp.connect();
            Log.d(TAG, "Connected to SFTP channel");
            sftp.put(localFile, remoteDir + new File(localFile).getName());
            Log.d(TAG, "File upload success");
            sftp.disconnect();
            session.disconnect();
        } catch (JSchException | SftpException e) {
            Log.e(TAG, "File upload failed", e);
            Log.e(TAG, "Exception: " + e.getMessage());
            if (e.getCause() != null) {
                Log.e(TAG, "Caused by: " + e.getCause().getClass().getName() + ": " + e.getCause().getMessage());
            }
        }
    }
    private void writeDataToFile() {
        Log.d(TAG, "writeDataToFile:"+LOCAL_FILE_PATH);
        DatabaseHelper databaseHelper = new DatabaseHelper(this);
        SQLiteDatabase db = databaseHelper.getReadableDatabase();
        Cursor cursor = db.rawQuery("SELECT * FROM " + DatabaseHelper.TABLE_NAME, null);
        File file = new File(LOCAL_FILE_PATH);
        try (FileOutputStream fos = new FileOutputStream(file)) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
            int totalCount = 0;
            int successCount = 0;
            int failureCount = 0;
            while (cursor.moveToNext()) {
                String url = cursor.getString(cursor.getColumnIndex(DatabaseHelper.COLUMN_URL));
                long time = cursor.getLong(cursor.getColumnIndex(DatabaseHelper.COLUMN_TIME));
                int status = cursor.getInt(cursor.getColumnIndex(DatabaseHelper.COLUMN_STATUS));
                long timestamp = cursor.getLong(cursor.getColumnIndex(DatabaseHelper.COLUMN_TIMESTAMP));
                String network_ip = cursor.getString(cursor.getColumnIndex(DatabaseHelper.COLUMN_NETWORK_IP));
                String datetime = sdf.format(new Date(timestamp));
                String data = String.format(Locale.getDefault(), "Index:%d,Network:%s,URL:%s,Time:%d ms,Status:%d,Datetime:%s\n", totalCount + 1, network_ip, url, time, status, datetime);
                fos.write(data.getBytes());
                totalCount++;
                if (status == 200) {
                    successCount++;
                } else {
                    failureCount++;
                }
            }
            double successRate = (double) successCount / totalCount * 100;
            String stats = String.format(Locale.getDefault(), "总请求次数: %d, 成功次数: %d, 失败次数: %d, 成功率: %.2f%%\n", totalCount, successCount, failureCount, successRate);
            fos.write(stats.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            cursor.close();
            db.close();
        }
    }
}

NetworkMonitorReceiver

NetworkMonitorReceiver是一个继承自BroadcastReceiver的广播接收器,它可以接收系统或应用发送的广播,并做出相应的处理。我们重写了它的onReceive方法,在这个方法中,我们做了以下一件事:

  • 启动一个定时器和一个定时任务,每隔一定时间就启动NetworkMonitorService

代码如下:

package com.xxx.factorytest.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.xxx.factorytest.service.NetworkMonitorService;
import java.util.Timer;
import java.util.TimerTask;
public class NetworkMonitorReceiver extends BroadcastReceiver {
    // 定义一个定时器对象,用来执行定时任务
    private Timer timer;
    // 定义一个定时任务对象,用来启动后台服务
    private TimerTask timerTask;
    // 定义一个常量,表示每隔多少毫秒执行一次
    private static final long PERIOD = 1000;
    // 重写onReceive方法,在接收到广播时启动定时器和定时任务
    @Override
    public void onReceive(Context context, Intent intent) {
        // Toast.makeText(context, "upload-->", Toast.LENGTH_SHORT).show();
        // 创建一个定时器对象
        timer = new Timer();
        // 创建一个定时任务对象
        timerTask = new TimerTask() {
            @Override
            public void run() {
                // 启动后台服务
                NetworkMonitorService.startService(context);
            }
        };
        // 启动定时器和定时任务,延迟0毫秒,每隔1秒执行一次
        timer.schedule(timerTask, 0, PERIOD);
    }
}

FileUploadReceiver

FileUploadReceiver也是一个继承自BroadcastReceiver的广播接收器,它可以接收系统或应用发送的广播,并做出相应的处理。我们重写了它的onReceive方法,在这个方法中,我们做了以下一件事:

  • 启动一个定时器和一个定时任务,每隔一定时间就启动FileUploadService

代码如下:

package com.xxx.factorytest.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.btf.factorytest.service.FileUploadService;
import java.util.Timer;
import java.util.TimerTask;
public class FileUploadReceiver extends BroadcastReceiver {
    // 定义一个定时器对象,用来执行定时任务
    private Timer timer;
    // 定义一个定时任务对象,用来启动后台服务
    private TimerTask timerTask;
    // 定义一个常量,表示每隔多少毫秒执行一次
    private static final long PERIOD = 10000;
    // 重写onReceive方法,在接收到广播时启动定时器和定时任务
    @Override
    public void onReceive(Context context, Intent intent) {
       // Toast.makeText(context, "upload-->", Toast.LENGTH_SHORT).show();
        // 创建一个定时器对象
        timer = new Timer();
        // 创建一个定时任务对象
        timerTask = new TimerTask() {
            @Override
            public void run() {
                // 启动后台服务
                FileUploadService.startService(context);
            }
        };
        // 启动定时器和定时任务,延迟0毫秒,每隔10秒执行一次
        timer.schedule(timerTask, 0, PERIOD);
    }
}

DatabaseHelper

DatabaseHelper是一个继承自SQLiteOpenHelper的数据库操作类,它可以创建和管理本地数据库。我们重写了它的onCreate和onUpgrade方法,在这些方法中,我们做了以下几件事:

  • 创建一个名为network_test的数据库表,用来存储测试结果
  • 定义了表中的五个字段:url、time、status、timestamp、network_ip,分别表示请求的URL、请求花费的时间、响应的状态码、请求的时间戳、请求的网络类型和IP地址
  • 定义了一些常量,用来表示表名和字段名

我们还定义了两个方法:insertData和queryData,分别用来插入和查询数据。

代码如下:

public class DatabaseHelper extends SQLiteOpenHelper {
    // 定义数据库的名称和版本号
    private static final String DATABASE_NAME = "network_test.db";
    private static final int DATABASE_VERSION = 1;
    // 定义表名和字段名的常量
    public static final String TABLE_NAME = "network_test";
    public static final String COLUMN_URL = "url";
    public static final String COLUMN_TIME = "time";
    public static final String COLUMN_STATUS = "status";
    public static final String COLUMN_TIMESTAMP = "timestamp";
    public static final String COLUMN_NETWORK_IP = "network_ip";
    // 定义创建表的SQL语句
    private static final String CREATE_TABLE_SQL = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + "(" +
            COLUMN_URL + " TEXT," +
            COLUMN_TIME + " INTEGER," +
            COLUMN_STATUS + " INTEGER," +
            COLUMN_TIMESTAMP + " INTEGER," +
            COLUMN_NETWORK_IP + " TEXT" +
            ")";
    // 定义删除表的SQL语句
    private static final String DROP_TABLE_SQL = "DROP TABLE IF EXISTS " + TABLE_NAME;
    // 构造方法,调用父类的构造方法,并传入数据库的名称和版本号
    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }
    // 重写onCreate方法,在创建数据库时执行创建表的SQL语句
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_TABLE_SQL);
    }
    // 重写onUpgrade方法,在升级数据库时执行删除表和创建表的SQL语句
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL(DROP_TABLE_SQL);
        db.execSQL(CREATE_TABLE_SQL);
    }
    // 定义一个插入数据的方法,接收五个参数,分别表示请求的URL、请求花费的时间、响应的状态码、请求的时间戳、请求的网络类型和IP地址,并返回插入结果(true或false)
    public boolean insertData(String url, long time, int status, long timestamp, String network_ip) {
        // 获取一个可写的数据库对象
        SQLiteDatabase db = getWritableDatabase();
        // 创建一个ContentValues对象,用来存放要插入的数据
        ContentValues values = new ContentValues();
        values.put(COLUMN_URL, url);
        values.put(COLUMN_TIME, time);
        values.put(COLUMN_STATUS, status);
        values.put(COLUMN_TIMESTAMP, timestamp);
        values.put(COLUMN_NETWORK_IP, network_ip);
        // 调用insert方法,将数据插入到数据库中,并返回插入结果(-1表示失败,其他表示成功)
        long result = db.insert(TABLE_NAME, null, values);
        // 关闭数据库对象
        db.close();
        // 判断插入结果,如果不等于-1,表示成功,返回true,否则返回false
        return result != -1;
    }
    // 定义一个查询数据的方法,返回一个Cursor对象,用来遍历查询结果
    public Cursor queryData() {
        // 获取一个可读的数据库对象
        SQLiteDatabase db = getReadableDatabase();
        // 调用query方法,查询所有的数据,并按照时间戳降序排序
        Cursor cursor = db.query(TABLE_NAME, null, null, null, null, null, COLUMN_TIMESTAMP + " DESC");
        // 返回Cursor对象
        return cursor;
    }
}

NetworkHelper

NetworkHelper是一个网络操作类,它提供了两个静态方法:getCurrentNetworkType和getCurrentIpAddress,分别用来获取当前的网络类型和IP地址。

代码如下:

public class NetworkHelper {
    // 定义一个获取当前网络类型的方法,接收一个Context对象作为参数,返回一个字符串表示网络类型
    public static String getCurrentNetworkType(Context context) {
        // 获取一个ConnectivityManager对象,用来管理网络连接
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        // 获取当前激活的网络信息
        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
        // 判断网络信息是否为空,如果为空,表示没有网络连接,返回"NONE"
        if (networkInfo == null) {
            return "NONE";
        }
        // 获取当前网络的类型
        int type = networkInfo.getType();
        // 根据不同的类型,返回不同的字符串
        switch (type) {
            case ConnectivityManager.TYPE_WIFI:
                return "WIFI";
            case ConnectivityManager.TYPE_MOBILE:
                return "MOBILE";
            case ConnectivityManager.TYPE_ETHERNET:
                return "ETHERNET";
            default:
                return "UNKNOWN";
        }
    }
    // 定义一个获取当前IP地址的方法,接收一个Context对象作为参数,返回一个字符串表示IP地址
    public static String getCurrentIpAddress(Context context) {
        // 获取一个WifiManager对象,用来管理WIFI连接
        WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        // 获取当前WIFI连接的信息
        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
        // 获取当前WIFI分配的IP地址,是一个整数
        int ipAddress = wifiInfo.getIpAddress();
        // 将整数转换为字符串,使用点号分隔四个字节
        String ip = (ipAddress & 0xFF) + "." +
                ((ipAddress >> 8) & 0xFF) + "." +
                ((ipAddress >> 16) & 0xFF) + "." +
                ((ipAddress >> 24) & 0xFF);
        // 返回IP地址字符串
        return ip;
    }
}

注册组件和申请权限

在AndroidManifest.xml文件中,我们需要注册我们的四个组件:两个后台服务和两个广播接收器,并指定它们的名称和属性。还需要申请一些必要的权限,如访问网络、访问WIFI、访问外部存储等。代码如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.networktest">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
      <!-- 定义一个后台服务的组件,使用JobIntentService类 -->
        <service
            android:name=".service.NetworkMonitorService"
            android:permission="android.permission.BIND_JOB_SERVICE"
            android:exported="false" />
        <!-- 定义一个后台服务的组件,使用JobIntentService类 -->
        <service
            android:name=".service.FileUploadService"
            android:permission="android.permission.BIND_JOB_SERVICE"
            android:exported="false" />
        <!-- 定义一个广播接收器的组件,使用FileUploadReceiver类 -->
        <receiver
            android:name=".receiver.FileUploadReceiver"
            android:exported="false">
            <!-- 指定要接收的广播类型,比如开机启动,网络变化等 -->
            <intent-filter>
                <action android:name="com.example.fileupload.ACTION_START_UPLOAD" />
            </intent-filter>
        </receiver>
        <receiver
            android:name=".receiver.NetworkMonitorReceiver"
            android:exported="false">
            <!-- 指定要接收的广播类型,比如开机启动,网络变化等 -->
            <intent-filter>
                <action android:name="com.example.networkmonitor.ACTION_START_MONITOR" />
            </intent-filter>
        </receiver>

测试

  • 在远程服务器上查看上传的文件,并分析测试结果

总结

本文介绍了一个Android网络连接稳定性测试解决方案,它可以对不同类型的网络和服务器进行测试,并记录和上传测试结果。

希望本文对你有所帮助,如果你有任何问题或建议,欢迎在评论区留言。谢谢!

相关文章
|
2月前
|
机器学习/深度学习 PyTorch 算法框架/工具
目标检测实战(一):CIFAR10结合神经网络加载、训练、测试完整步骤
这篇文章介绍了如何使用PyTorch框架,结合CIFAR-10数据集,通过定义神经网络、损失函数和优化器,进行模型的训练和测试。
114 2
目标检测实战(一):CIFAR10结合神经网络加载、训练、测试完整步骤
|
21天前
|
存储 安全 网络安全
云计算与网络安全:探索云服务中的信息安全挑战与解决方案
【10月更文挑战第33天】在数字化时代的浪潮中,云计算以其灵活性、可扩展性和成本效益成为企业数字化转型的核心动力。然而,随之而来的网络安全问题也日益突出,成为制约云计算发展的关键因素。本文将深入探讨云计算环境中的网络安全挑战,分析云服务的脆弱性,并提出相应的信息安全策略和最佳实践。通过案例分析和代码示例,我们将展示如何在云计算架构中实现数据保护、访问控制和威胁检测,以确保企业在享受云计算带来的便利的同时,也能够维护其信息系统的安全和完整。
|
22天前
|
机器学习/深度学习 自然语言处理 前端开发
前端神经网络入门:Brain.js - 详细介绍和对比不同的实现 - CNN、RNN、DNN、FFNN -无需准备环境打开浏览器即可测试运行-支持WebGPU加速
本文介绍了如何使用 JavaScript 神经网络库 **Brain.js** 实现不同类型的神经网络,包括前馈神经网络(FFNN)、深度神经网络(DNN)和循环神经网络(RNN)。通过简单的示例和代码,帮助前端开发者快速入门并理解神经网络的基本概念。文章还对比了各类神经网络的特点和适用场景,并简要介绍了卷积神经网络(CNN)的替代方案。
|
29天前
|
编解码 安全 Linux
网络空间安全之一个WH的超前沿全栈技术深入学习之路(10-2):保姆级别教会你如何搭建白帽黑客渗透测试系统环境Kali——Liinux-Debian:就怕你学成黑客啦!)作者——LJS
保姆级别教会你如何搭建白帽黑客渗透测试系统环境Kali以及常见的报错及对应解决方案、常用Kali功能简便化以及详解如何具体实现
|
1月前
|
存储 安全 网络安全
云计算与网络安全:技术、挑战与解决方案
【10月更文挑战第24天】随着云计算技术的飞速发展,越来越多的企业和个人开始将数据和应用迁移到云端。然而,云服务的安全性问题也日益凸显,成为制约云计算发展的重要因素。本文将深入探讨云计算与网络安全之间的关系,分析当前面临的主要安全挑战,并提出相应的解决方案。通过阅读本文,读者将能够更好地理解云计算环境下的安全问题,并掌握应对策略。
|
2月前
|
网络协议 Shell 网络安全
解决两个 Android 模拟器之间无法网络通信的问题
让同一个 PC 上运行的两个 Android 模拟器之间能相互通信,出(qiong)差(ren)的智慧。
24 3
|
2月前
|
机器学习/深度学习 数据采集 算法
目标分类笔记(一): 利用包含多个网络多种训练策略的框架来完成多目标分类任务(从数据准备到训练测试部署的完整流程)
这篇博客文章介绍了如何使用包含多个网络和多种训练策略的框架来完成多目标分类任务,涵盖了从数据准备到训练、测试和部署的完整流程,并提供了相关代码和配置文件。
59 0
目标分类笔记(一): 利用包含多个网络多种训练策略的框架来完成多目标分类任务(从数据准备到训练测试部署的完整流程)
|
25天前
|
安全 搜索推荐 程序员
深入探索Android系统的碎片化问题及其解决方案
在移动操作系统的世界中,Android以其开放性和灵活性赢得了广泛的市场份额。然而,这种开放性也带来了一个众所周知的问题——系统碎片化。本文旨在探讨Android系统碎片化的现状、成因以及可能的解决方案,为开发者和用户提供一种全新的视角来理解这一现象。通过分析不同版本的Android系统分布、硬件多样性以及更新机制的影响,我们提出了一系列针对性的策略,旨在减少碎片化带来的影响,提升用户体验。
|
29天前
|
人工智能 安全 Linux
网络空间安全之一个WH的超前沿全栈技术深入学习之路(4-2):渗透测试行业术语扫盲完结:就怕你学成黑客啦!)作者——LJS
网络空间安全之一个WH的超前沿全栈技术深入学习之路(4-2):渗透测试行业术语扫盲完结:就怕你学成黑客啦!)作者——LJS
|
29天前
|
安全 大数据 Linux
网络空间安全之一个WH的超前沿全栈技术深入学习之路(3-2):渗透测试行业术语扫盲)作者——LJS
网络空间安全之一个WH的超前沿全栈技术深入学习之路(3-2):渗透测试行业术语扫盲)作者——LJS