1.OkHttp3源码详解之 okhttp连接池复用机制(一)
2.网络使用wireshark抓包 分析websocket协议 以及TCP三次握手(实测)
3.nginx调用openssl函数源码分析
OkHttp3源码详解之 okhttp连接池复用机制(一)
提高网络性能优化,握手握手关键在于降低延迟和提升响应速度。源码
在浏览器中发起请求时,程序header部分通常如下所示:
keep-alive是编写指浏览器与服务端之间保持长连接,这种连接可以复用。握手握手在HTTP1.1中,源码股票源码背离公式它默认是程序开启的。
连接复用为何能提高性能?通常,编写在发起http请求时,握手握手我们需要完成TCP的源码三次握手、传输数据,程序最后释放连接。编写三次握手的握手握手过程可以参考这里:TCP三次握手详解及释放连接过程。
一次响应的源码过程:
在高并发的请求连接情况下或同一客户端多次频繁的请求操作中,无限制地创建连接会导致性能低下。程序
如果使用keep-alive,在timeout空闲时间内,连接不会关闭,色柱macd源码相同的重复请求将复用原有的connection,减少握手的次数,大幅提高效率。
并非keep-alive的timeout设置时间越长,性能就越好。长时间不关闭会导致过多的僵尸连接和泄露连接出现。
那么,OkHttp3在客户端是如何实现类似keep-alive的机制的?
连接池的类位于okhttp3.ConnectionPool。我们的目标是了解如何在timeout时间内复用connection,并有效地对其进行回收清理操作。
其成员变量代码片段:
excutor:线程池,用于检测闲置socket并进行清理。
connections:connection缓存池。Deque是一个双端列表,支持在头尾插入元素,这里用作LIFO(后进先出)堆栈,多用于缓存数据。复数补码转源码
routeDatabase:用于记录连接失败的router。
2.1 缓存操作:
ConnectionPool提供对Deque进行操作的方法,包括put、get、connectionBecameIdle、evictAll等操作,分别对应放入连接、获取连接、移除连接、移除所有连接操作。
2.2 连接池的清理和回收:
在观察ConnectionPool的成员变量时,我们了解到一个Executor线程池用于清理闲置的连接。注释中这样解释:
Background threads are used to cleanup expired connections
我们在put新连接到队列时,会先执行清理闲置连接的线程。调用的正是executor.execute(cleanupRunnable);方法。观察cleanupRunnable:
线程中不停调用Cleanup清理的动作并立即返回下次清理的间隔时间。继而进入wait等待之后释放锁,android系统源码版本继续执行下一次的清理。所以可能理解成它是个监测时间并释放连接的后台线程。
了解cleanup动作的过程。这里就是如何清理所谓闲置连接的流程。怎么找到闲置的连接是主要解决的问题。
在遍历缓存列表的过程中,使用连接数目inUseConnectionCount和闲置连接数目idleConnectionCount的计数累加值都是通过pruneAndGetAllocationCount()是否大于0来控制的。那么很显然,pruneAndGetAllocationCount()方法就是用来识别对应连接是否闲置的。>0则不闲置,否则就是闲置的连接。
进入观察:
好了,原先存放在RealConnection中的allocations派上用场了。遍历StreamAllocation弱引用链表,移除为空的引用,遍历结束后返回链表中弱引用的数量。所以可以看出List>就是狄马克td源码一个记录connection活跃情况的List。>0表示活跃,=0表示空闲。StreamAllocation在列表中的数量就是物理socket被引用的次数。
解释:StreamAllocation被高层反复执行aquire与release。这两个函数在执行过程中其实是在一直在改变Connection中的List大小。
搞定了查找闲置的connection操作,我们回到cleanup的操作。计算了inUseConnectionCount和idleConnectionCount之后,程序又根据闲置时间对connection进行了一个选择排序,选择排序的核心是:
通过对比最大闲置时间选择排序可以方便地查找出闲置时间最长的一个connection。如此一来,我们就可以移除这个没用的connection了!
总结:清理闲置连接的核心主要是引用计数器List>和选择排序算法以及excutor的清理线程池。
网络使用wireshark抓包 分析websocket协议 以及TCP三次握手(实测)
深入理解网络通信,光是理论研究或阅读源码难以获得直观感受。借助抓包工具Wireshark进行实际数据抓取分析,能更直观地理解协议细节,尤其是WebSocket和TCP三次握手。
Wireshark是一款功能强大的网络封包分析工具,广泛应用于网络协议分析与调试。作为开源软件,其源码可在GitHub上获取,对深入研究Wireshark内部机制大有裨益。对于Wireshark的使用方法,可参阅其官方文档。
WebSocket的通信基础是帧(frame),单个帧构成完整消息。WebSocket数据帧格式遵循RFC标准,由FIN、操作码(Opcode)等字段组成,操作码决定后续数据载荷的解析方式。
在建立WebSocket连接过程中,通过TCP三次握手完成。Wireshark能够实时抓取连接建立过程中的数据包。
具体操作步骤如下:
1. 使用Wireshark选择网络适配器并过滤IP地址。
2. 打开浏览器访问HTML页面。
3. 保持连接状态秒钟。
4. 关闭浏览器。
抓包数据示例:
1-3步:TCP三次握手过程
1. A主机发送SYN(Seq=0),表示连接请求。
2. B主机响应ACK(Seq=1),同时发送SYN(Seq=0),表示接收请求并准备建立连接。
3. A主机回应ACK(Seq=1),同时发送SYN(Seq=1),完成三次握手。
随后,A主机发送HTTP协议信息,表明请求升级至WebSocket协议。
紧接着,B主机通过ACK应答确认,发送HTTP协议信息表示同意升级,并成功切换。
接下来,A主机进行ACK应答,B主机发出准备发送数据的请求,包含“PSH”标识。
A主机再次进行ACK应答,B主机发送WebSocket协议数据。
分析此过程与WebSocket帧格式对照,发现:
当前帧的FIN标记为1,指示此帧为消息末尾。
操作码值为2,表示二进制格式。
帧无掩码,数据长度为字节,数据部分由用户自定义。
通过Wireshark抓取的实际数据,能清晰地了解WebSocket和TCP三次握手的交互过程,直观展示协议的执行细节与数据结构。
nginx调用openssl函数源码分析
本文分为两部分,分别是nginx部分和openssl部分。在nginx部分,首先在ngx_http_init_connection函数中,将recv→handler设置为ngx_http_ssl_handshake。然后,将这个读取时间加入到epoll中,主要目的是分析handshake函数。
在handshake阶段,首先接收client hello并完成初始化。接着调用ngx_ssl_handshake函数,该函数内部会调用openssl的ssl_do_handshake函数。在进行握手操作时,会使用openssl的async job库。
在openssl部分,首先通过get context进行初始化,并分配内存创建堆栈,将函数放入其中。接着,通过makecontext创建并运行async_start_func,该函数实际调用job中的指定函数。关键在于pause job,这通过swapcontext在func中被调用时立即切换栈信息。在返回到start_job主函数后,发现其为死循环任务,会根据job的状态进行返回,这一状态在nginx中接收时表现为SSL_ERROR_WANT_ASYNC。