Android 使用okhttp监控网络数据

news2024/12/26 9:32:52

这里使用Okhttp写了一个demo来监听网络请求过程中的一系列数据,包括当前网络类型、请求体、响应体大小,url,请求方式,当然还有本次核心获取域名解析时长,建立连接时长,保持连接时长,请求总时长这些数据。

一次网络请求经历了哪些过程

通过域名访问的方式来请求网络时,会经历下列过程:
1.DNS解析:通过域名服务器或者本地host将域名解析成ip地址
2.建立连接:三次握手
3.发送数据:通过GET/POST/PUT等方式将数据(header和body)发送给服务器,
4.接受数据:接受服务器返回数据:响应头和body
5.断开链接:四次挥手断开链接

OkHttp库实现了哪些网络请求过程的状态回调
在这里插入图片描述OkhttpClient的Builder类可以调用eventListener设置EventListener,EventListener会进行回调如上图的各个事件节点。

所有方法为:

public abstract class EventListener {
    public void callStart(Call call) {}
    // 域名解析
    public void dnsStart(Call call, String domainName) {}
    public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) {}
    // 开始连接
    public void connectStart(call, route.socketAddress(), proxy){}
    // 释放当前Transmitter的RealConnection
    public void connectionReleased(Call call, Connection connection) {}
    public void connectionAcquired(call, result){};
    // 请求
    public void requestHeadersStart(@NotNull Call call){}
    public void requestHeadersEnd(@NotNull Call call, @NotNull Request request) {}
    // 响应
    public void requestBodyStart(@NotNull Call call) {}
    public void requestBodyEnd(@NotNull Call call, long byteCount) {}
    // 结束
    public void callEnd(Call call) {}
    // 失败
    public void callFailed(Call call, IOException ioe) {}
}

流程解释:

1.callStart:一次请求开始了
2.dns:dns解析过程
3.connectStart: 开始建立连接了
4.secureConnect: 开始建立TSL安全链接
5.connectEnd: 链接建立结束:可能建立失败,失败后可以重试
6.requestHeaders:发送请求头
7.requestBody:发送请求body
8.responseHeaders:客户端接受响应头
9.responseBody:客户端接受响应body
10.connectionReleased:链接释放
11.callEnd:一次请求结束

添加日志拦截器获取请求体、响应体大小和响应内容:

class LoggingInterceptor : Interceptor {
    private val byteCount = 1024 * 1024

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        //chain里面包含了request和response,按需获取

        val request = chain.request()
        val response = chain.proceed(request)

        Log.v(HTTP, "(请求地址): ${request.url()}")
        Log.v(HTTP, "请求方式: ${request.method()}")

        if (request.body() == null) {
            Log.v(HTTP, "(请求体大小): 0")
        } else {
            val requestBody = request.body()
            Log.v(HTTP, "(请求体大小): ${requestBody?.contentLength()}")
        }

        val responseBody = response.peekBody(byteCount.toLong())

        Log.v(HTTP, "(响应体大小): ${responseBody.contentLength()}")
        Log.v(HTTP, "响应内容: ${responseBody.string()}")
        return response
    }
}

自定义EventListener获取各个数据:

import android.util.Log
import com.apus.networkmonitor.constants.Tags
import okhttp3.*
import java.io.IOException
import java.net.InetAddress
import java.net.InetSocketAddress
import java.net.Proxy
import java.util.concurrent.TimeUnit

/**
 * @author: libo
 * @date: 2023/4/26 09:38
 * @Description: 监听okhttp请求,包括连接总时长和请求总时长
 */
open class CustomOkEventListener: EventListener() {
    private var dnsStart: Long = 0 //dns开始解析时间
    private var connectStart: Long = 0  //开始连接时间
    private var callStart: Long = 0  //开始请求时间
    private var connectAquire: Long = 0  //连接获取时间

    override fun callStart(call: Call) {
        Log.v(Tags.CALL, "callStart")

        callStart = System.nanoTime()
    }

    override fun dnsStart(call: Call, domainName: String) {
        Log.v(Tags.CALL, "dnsStart")

        dnsStart = System.nanoTime()
    }

    override fun dnsEnd(call: Call, domainName: String, inetAddressList: MutableList<InetAddress>) {
        Log.v(Tags.CALL, "dnsEnd")

        var dnsEnd = System.nanoTime()
        var duration = TimeUnit.NANOSECONDS.toMillis(dnsEnd - dnsStart)
        Log.v(Tags.HTTP, "(域名解析时长): $duration ms")
    }

    override fun connectStart(call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy) {
        Log.v(Tags.CALL, "connectStart")

        connectStart = System.nanoTime()
    }

    override fun connectEnd(
        call: Call,
        inetSocketAddress: InetSocketAddress,
        proxy: Proxy,
        protocol: Protocol?
    ) {
        Log.v(Tags.CALL, "connectEnd")

        connectAquire = System.nanoTime()
        var duration = TimeUnit.NANOSECONDS.toMillis(connectAquire - connectStart)
        Log.v(Tags.HTTP, "(建连时长): $duration ms")
    }

    override fun connectionAcquired(call: Call, connection: Connection) {
        Log.v(Tags.CALL, "connectionAcquired")
    }

    override fun connectionReleased(call: Call, connection: Connection) {
        Log.v(Tags.CALL, "connectionReleased")

        var connectReleased = System.nanoTime()
        var duration = TimeUnit.NANOSECONDS.toMillis(connectReleased - connectAquire)
        Log.v(Tags.HTTP, "(连接保持时长): $duration ms")
    }

    override fun callEnd(call: Call) {
        Log.v(Tags.CALL, "callEnd")

        var callEnd = System.nanoTime()
        var duration = TimeUnit.NANOSECONDS.toMillis(callEnd - callStart)
        Log.v(Tags.HTTP, "(请求总时长): $duration ms")
    }

    override fun callFailed(call: Call, ioe: IOException) {
        Log.v(Tags.CALL, "callFailed")

        var callEnd = System.nanoTime()
        var duration = TimeUnit.NANOSECONDS.toMillis(callEnd - callStart)
        Log.v(Tags.HTTP, "(请求总时长): $duration ms")
    }
}

时间的计算用的是System.nanoTime(),返回正在运行的Java虚拟机的高分辨率时间源的当前值,单位为纳秒。

最后,将CustomOkEventListener设置给okhttpClient:

val builder = OkHttpClient.Builder()
                .retryOnConnectionFailure(true) //失败重连
                .addInterceptor(LoggingInterceptor()) //日志拦截器
                .eventListener(CustomOkEventListener()) //统计请求链路各时长
                builder.build()

Dns解析时长或者自定义Dns,然后设置给okhttpclient:

class CustomDns: Dns {

    override fun lookup(hostname: String?): MutableList<InetAddress> {
        var start = System.nanoTime()  //返回正在运行的Java虚拟机的当前值,高分辨率时间源,单位为纳秒
        val lookup = Dns.SYSTEM.lookup(hostname)  //操作系统查找域名
        var end = System.nanoTime()
        var duration = TimeUnit.NANOSECONDS.toMillis(end - start)
        Log.v(Tags.HTTP, "dns_time_l(域名解析时长): $duration " + "ms")
        return lookup
    }
}

打印统计结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/674432.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《C++ Primer》--学习6

IO库 IO类 为了支持使用宽字符的语言&#xff0c;标准库定义了一组类型和对象来操纵 wchar_t 类型的数据。宽字符版本的类型和函数的名字以一个 w 开始。wcin wcout 和 wcerr 是分别对应 cin cout 和 cerr 的宽字符版本对象 IO类型之间的关系 类型 ifstream 和 istringstream…

Vuex 状态管理 —— 核心store

在上一篇当中讲到关于接口请求函数获取数据&#xff0c;拿到 response.data &#xff0c;简化调用&#xff0c;那么在拿到请求的响应数据之后呢&#xff1f;在前面讲到组件间的通信当中&#xff0c;如父子通信(父传子props,子传父$emit)以及组件与组件之前不能通过直接通信&…

【33】用 Docker 部署 Prometheus + Grafana 监控平台

一. Docker部署Prometheus 1.1 下载prom/prometheus镜像 docker pull prom/prometheus 1.2 启动prometheus容器 docker run -itd --nameprometheus -p 9090:9090 prom/prometheus 打开本地http://localhost:9090/ 说明启动成功 1.3 将容器的配置文件复制出来 docker cp pr…

深入理解深度学习——GPT(Generative Pre-Trained Transformer):在不同任务中使用GPT

分类目录&#xff1a;《自然语言处理从入门到应用》总目录 GPT预训练语言模型作为一个标准的语言模型&#xff0c;其输入和输出是固定的&#xff0c;即输入一个词序列&#xff0c;输出该词序列的下一个词。《深入理解深度学习——GPT&#xff08;Generative Pre-Trained Transf…

GAMES101 笔记 Lecture06 Rasterization2(Antialiasing and Z-Buffering)

目录 Antialiasing(反走样)Sampling is Ubiquitous in Computer Graphics(采样在计算机图形学中无处不在)Sampling Artifacts(Errors or Mistakes or Inaccuracies) in Computer Graphics(在计算机图形学中采样的瑕疵)Jaggies(Staircase Pattern)锯齿Moire Pattern in Imaging(…

[进阶]TCP通信实现BS架构,网站开发的原理,线程池优化BS架构

代码演示如下&#xff1a; 服务端 public class Server {public static void main(String[] args) throws Exception{System.out.println("服务端开启&#xff01;");//1.创建ServerSocket的对象&#xff0c;同时为服务端注册端口。ServerSocket serverSocket new…

Wang tile(王浩瓷砖)算法解决贴图平铺重复问题

Wang tile(王浩瓷砖) 大家好&#xff0c;我是阿赵。这次来解决一个贴图重复的问题。 一、问题 做一篇很大面积的草地&#xff0c;一般思路是建立一个地面的面片&#xff0c;然后在材质球里面给他做一个Tiling平铺&#xff0c;增大重复次数。这样整个地面都可以被草地的贴图铺满…

Spring Boot 如何使用 @Validated 注解进行数据校验

Spring Boot 如何使用 Validated 注解进行数据校验 在开发应用程序时&#xff0c;数据校验通常是不可避免的。Spring Boot 提供了许多选项来验证应用程序中的数据&#xff0c;其中一个选项是使用 Validated 注解。本文将介绍如何使用 Validated 注解进行数据校验&#xff0c;并…

操作系统-操作系统结构

✅作者简介&#xff1a;人工智能专业本科在读&#xff0c;喜欢计算机与编程&#xff0c;写博客记录自己的学习历程。 &#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&…

【计算机组成原理】Yy-z02硬布线模型机设计

目录 一、Yy-z02模型机的系统结构 二、Yy-z02模型机的数据通路 三、Yy-z02模型机的指令执行 四、Yy-z02模型机的硬布线控制器 一、Yy-z02模型机的系统结构 指令系统的实现 <--- 构造它的硬件系统 硬件系统构造过程&#xff1a; 分析指令格式和各指令的功能确定部件连…

《机器学习公式推导与代码实现》chapter16-集成学习对比与调参

《机器学习公式推导与代码实现》学习笔记&#xff0c;记录一下自己的学习过程&#xff0c;详细的内容请大家购买作者的书籍查阅。 集成学习&#xff1a;对比与调参 虽然现在深度学习大行其道&#xff0c;但以XGBoost、LightGBM、CatBoost为代表的Boosting算法仍有其广泛的用武…

【Applied Algebra】有限状态机和模型检测初探

【Applied Algebra】有限状态机和模型检测初探 摘要:有限状态机(FSM)和模型检测有密切的联系。有限状态机提供了一种用状态转换图来表示系统行为的简单方法。而模型检测是一种针对形式化模型&#xff08;例如有限状态机&#xff09;的验证技术&#xff0c;旨在自动验证模型是否…

css基础(一)

目录 思维导图 ​一、css简介 1.1 css语法规范 1.2 css代码规格 1. 样式格式书写 2. 样式大小写 3. 空格规范 二、css选择器 2.1 CSS 选择器的作用 2.2 选择器分类 2.3 标签选择器 2.4 类选择器 2.4 类选择器-多类名 2.5 id 选择器 2.6 通配符选择器 2.7 基础选择器总结 三、CS…

D. Running Miles(公式转换)

Problem - D - Codeforces 有一条长为n的街道&#xff0c;其中第i个景点距离街道起点i英里。第i个景点的美丽值为bi。你想要在离街道起点l英里和r英里处开始和结束慢跑。当你跑步时&#xff0c;你会看到你经过的景点&#xff08;包括起点和终点处的景点&#xff09;。你对沿途慢…

Microsoft365有用吗?2023最新版office有哪些新功能?

office自97版到现在已有20多年&#xff0c;一直是作为行业标准&#xff0c;格式和兼容性好&#xff0c;比较正式&#xff0c;适合商务使用。包含多个组件&#xff0c;除了常用的word、excel、ppt外&#xff0c;还有收发邮件的outlook、管理数据库的access、排版桌面的publisher…

CENTOS上的网络安全工具(二十五)SPARK+NetSA Security Tools容器化部署(1)

一、第三代YAF YAF&#xff08;Yet Another Flowmeter&#xff09;是作为CERT NetSA安全工具套件的传感器部分存在的&#xff0c;支持输入实时数据流和PCAP文件&#xff0c;解析并输出流数据&#xff0c;或针对特定协议的深包检测元数据。目前&#xff0c;YAF在整个系统的作用如…

【js30天挑战】第三天:css变量

效果图&#xff1a; 学到的东西 HTML&CSS部分 css变量写法 //定义:root{ //:root 是 CSS 选择器&#xff0c;它匹配文档的根元素&#xff0c;也就是 html 元素。 --base:#FF0081;--spacing:10px;--blur:0px;} //使用img {filter: blur(var(--blur));}input: range类型…

Redis - 数据结构类型及使用场景详解(一)

一. 简介 Redis 是由 Salvatore Sanfilippo 编写的一个key-value存储系统&#xff0c;是跨平台的非关系型数据库。Redis是一个开源的&#xff0c;使用C语言编写的&#xff0c;遵守BSD协议&#xff0c;支持网络&#xff0c;可基于内存&#xff0c;分布式&#xff0c;可选持久性的…

EMC学习笔记(八)阻抗控制(二)

阻抗控制&#xff08;二&#xff09; 1.差分阻抗控制1.1 当介质厚度为5mil时的差分阻抗随差分线间距的变化趋势1.2 当介质厚度为13mil时的差分阻抗随差分线间距的变化趋势1.3 当介质厚度为25mil时的差分阻抗随差分线间距的变化趋势 2.屏蔽地线对阻抗的影响2.1 地线与信号线之间…

Day_54-55

目录 Day_54基于 M-distance 的推荐 一. 关于M-distance 的推荐 1. 基本数据说明 2. 推荐系统的算法过程 3. 简单思考 二. 代码复现 1. 数据导入 2. 代码的初始化 3. 核心代码 3.1 基础数据的构建 3.2 leave-out-leave测试 3.3 误差计算 Day_55基于 M-distance 的推荐 (续) …