源码角度,分析OkHttp实现WebSocket | 握手/保活/数据处理...

OkHttp实现WebSocket 阅读详情
19956127-c320139c78301c1e

wolfcstech | 作者

承香墨影 | 校对

https://www.wolfcstech.com/2017/02/23/OkHttp实现分析之Websocket | 原文

前段时间写了篇文章,讲解了如何使用 OkHttp 实现 WebSocket 通信,但是只停留在一些使用和理论上,分享出来各项数据还不错。本来想继续写一篇 OkHttp 关于 WebSocket 源码的分析文章。但搜索了一下,发现有一个个人博客写的文章非常详细,我就不再重复输出了,今天就给你带来这篇优秀的文章,希望对大家有帮助。

如果只对利用 OkHttp 实现 WebSocket 通信感兴趣,可以看看之前的文章《OkHttp实现WebSocket,包括鉴权和长连接保活及其原理》。


HTML5 拥有许多引人注目的新特性,WebSocket 就是其中之一。

WebSocket 一向有着 "Web 的 TCP" 之称。通常 WebSocket 都是用于 Web 的,用于构建实时的 Web 应用。它可以在浏览器和服务器之间提供一个基于 TCP 连接的双向通道。

WebSocket 协议本质上是一个基于 TCP 的协议。为了建立一个 WebSocket 连接,浏览器首先要向服务器发起一个 HTTP 请求,这个请求和通常的 HTTP 请求不同,包含了一些附加头信息,其中附加头信息 "Upgrade: WebSocket" 表明这是一个申请协议升级的 HTTP 请求,服务器端解析这些附加的头信息然后产生应答信息,返回给客户端,客户端和服务器端的 WebSocket 连接就建立起来了,双方就可以通过这个连接通道自由的传递信息,并且这个连接会持续存在直到客户端或者服务器端的某一方主动的关闭连接。

Websocket 同样可以用于移动端。尽管移动端 Android/iOS 的本地应用可以直接通过 Socket 与服务器建立连接,并定义自己的协议来解决 Web 中实时应用创建困难的问题,但 WebSocket 服务通常复用 Web 的 80 端口,且可以比较方便的基于 Web 服务器来实现,因而对于某些端口容易被封的网络环境而言,WebSocket 就变得非常有意义。

OkHttp 是在 2016 年 6 月 10 日发布的 3.4.1 版中添加的对 WebSocket 的支持的。本文通过分析 OkHttp-3.5.0 的 WebSocket 实现来学习一下这个协议。

一、OkHttp API 使用

在开始分析 WebSocket 的实现之前,我们先来看一下 OkHttp 的 WebSocket API 怎么用。

示例代码如下:


19956127-494bf9adfe644558.png

19956127-fbc193aee507832f.png

这个过程与发送 HTTP 请求的过程有许多相似之处,它们都需要创建 OkHttpClient 和 Request。然而它们不同的地方更多:

  1. WebSocket 请求通过 WebSocketListener 来接收连接的状态和活动,而 HTTP 请求则通过 Callback。同时请求的 URL 的 scheme 是 "ws" 或者是 "wss" (TLS 之上的 WebSocket),而不是 HTTP 的 "http" 和 "https";
  2. HTTP 请求的连接建立及执行需要基于 Request 和回调创建 Call,并调用 Call 的方法手动进行;而对于 WebSocket 请求,则在基于 Request 和回调创建 WebSocket 的时候,OkHttp 会自动发起连接建立的过程;
  3. 这也是 WebSocket 与 HTTP 最大的不同。对于 WebSocket,我们可以保存 WebSocket 对象,并在后续多次通过该对象向服务器发送数据;
  4. 通过回调可以获得更多 WebSocket 的状态变化。在连接建立、收到服务器发送回来的消息、服务器要关闭连接,以及出现 error 时,都能得到通知。不像 HTTP 请求那样,只在最后得到一个请求成功或者失败的结果;

后两点正是 WebSocket 全双工连接的体现。

二、OkHttp 的 WebSocket 实现

接着我们来看 OkHttp 的 WebSocket 实现。

WebSocket 包含两个部分,分别是握手和数据传输,数据传输又包括数据的发送,数据的接收,连接的保活,以及连接的关闭等,我们将分别分析这些过程。

2.1 连接握手

创建 WebSocket 的过程如下:

19956127-46e3482197808617.png

在这里会创建一个 RealWebSocket 对象,然后执行其 connect() 方法建立连接。RealWebSocket 对象的创建过程如下:

19956127-092bab9f9f92cdd1.png

这里最主要的是初始化了 key,以备后续连接建立及握手之用。Key 是一个 16 字节长的随机数经过 Base64 编码得到的。此外还初始化了 writerRunnable 等。

连接建立及握手过程如下:

19956127-028fadf2335e045d.png

连接建立及握手的过程主要是向服务器发送一个 HTTP 请求。这个 HTTP 请求的特别之处在于,它包含了如下的一些 Headers:

19956127-d2909540dee658b8.png

其中 Upgrade 和 Connection header 向服务器表明,请求的目的就是要将客户端和服务器端的通讯协议从 HTTP 协议升级到 WebSocket 协议,同时在请求处理完成之后,连接不要断开。

Sec-WebSocket-Key header 值正是我们前面看到的 key,它是 WebSocket 客户端发送的一个 base64 编码的密文,要求服务端必须返回一个对应加密的 "Sec-WebSocket-Accept" 应答,否则客户端会抛出 "Error during WebSocket handshake" 错误,并关闭连接。

来自于 HTTP 服务器的响应到达的时候,即是连接建立大功告成的时候,也就是热豆腐熟了的时候。

然而,响应到达时,尽管连接已经建立,还要为数据的收发做一些准备。这些准备中的第一步就是检查 HTTP 响应:

19956127-dbe454a45225c856.png

19956127-50c19abfb38204fe.png

根据 WebSocket 的协议,服务器端用如下响应,来表示接受建立 WebSocket 连接的请求:

  1. 响应码是 101;
  2. "Connection" header 的值为 "Upgrade",以表明服务器并没有在处理完请求之后把连接断开;
  3. "Upgrade" header 的值为 "websocket",以表明服务器接受后面使用 WebSocket 来通信;
  4. "Sec-WebSocket-Accept" header 的值为,key + WebSocketProtocol.ACCEPT_MAGIC 做 SHA1 hash,然后做 base64 编码,来做服务器接受连接的验证。关于这部分的设计的详细信息,可参考 《WebSocket 协议规范》。

为数据收发做准备的第二步是,初始化用于输入输出的 Source 和 Sink。Source 和 Sink 创建于之前发送 HTTP 请求的时候。这里会阻止在这个连接上再创建新的流。

19956127-facf05a92d043752.png

Streams 是一个 BufferedSource 和 BufferedSink 的 holder:

19956127-7d4322821633e32a.png

第三步是调用回调 onOpen()。

第四步是初始化 Reader 和 Writer:

19956127-4a5ec2765b35dc0c.png

OkHttp 使用 WebSocketReader 和 WebSocketWriter 来处理数据的收发。在发送数据时将数据组织成帧,在接收数据时则进行反向擦除,同时处理 WebSocket 的控制消息。

WebSocket 的所有数据发送动作,都会在单线程线程池的线程中,通过 WebSocketWriter 执行。在这里会创建 ScheduledThreadPoolExecutor 用于跑数据的发送操作。

WebSocket 协议中主要会传输两种类型的帧:

  1. 控制帧,主要是用于连接保活的 Ping 帧等;
  2. 数据载荷帧。在这里会根据用户的配置,调度 Ping 帧周期性地发送。我们在调用 WebSocket 的接口发送数据时,数据并不是同步发送的,而是被放在了一个消息队列中。发送消息的 Runnable 从消息队列中读取数据发送。其中会检查消息队列中是否有数据,如果有的话,会调度发送消息的 Runnable 执行。

第五步是配置 socket 的超时时间为 0,也就是阻塞 IO。

第六步执行 loopReader()。这实际上是进入了消息读取循环了,也就是数据接收的逻辑了。

2.2 数据发送

我们可以通过 WebSocket 接口的 send(String text) 和 send(ByteString bytes) 分别发送文本的和二进制格式的消息。

19956127-33f69bce5918a574.png

可以看到我们调用发送数据的接口时,做的事情主要是将数据格式化,构造消息,放进一个消息队列,然后调度 writerRunnable 执行。

此外,值得注意的是,当消息队列中的未发送数据,超出最大大小限制,WebSocket 连接会被直接关闭。对于发送失败过或被关闭了的 WebSocket,将无法再发送信息。

在 writerRunnable 中会循环调用 writeOneFrame() 逐帧发送数据,直到数据发完,或发送失败。在 WebSocket 协议中,客户端需要发送 4 种类型的帧:

  1. PING 帧
  2. PONG 帧
  3. CLOSE 帧
  4. MESSAGE 帧

PING 帧用于连接保活,它的发送是在 PingRunnable 中执行的,在初始化 Reader 和 Writer 的时候,就会根据设置调度执行或不执行。

除 PING 帧外的其它三种帧,都在 writeOneFrame() 中发送。PONG 帧是对服务器发过来的 PING 帧的响应,同样用于保活连接。

后面我们在分析连接的保活时会更详细的分析 PING 和 PONG 这两种帧。CLOSE 帧用于关闭连接,稍后我们在分析连接关闭过程时再来详细地分析。

这里我们主要关注用户数据发送的部分。PONG 帧具有最高的发送优先级。在没有 PONG 帧需要发送时,writeOneFrame() 从消息队列中取出一条消息,如果消息不是 CLOSE 帧,则主要通过如下的过程进行发送:

19956127-f72f7d854bd2ed0e.png

数据发送的过程可以总结如下:

  1. 创建一个 BufferedSink 用于数据发送;
  2. 将数据写入前面创建的 BufferedSink 中;
  3. 关闭 BufferedSink;
  4. 更新 queueSize 以正确地指示未发送数据的长度;

这里面的玄机主要在创建的 BufferedSink。创建的 Sink 是一个 FrameSink:

19956127-0797d0823e42f7be.png
image.png

FrameSink 的 write() 会先将数据写入一个 Buffer 中,然后再从这个 Buffer 中读取数据来发送。如果是第一次发送数据,同时剩余要发送的数据小于 8192 字节时,会延迟执行实际的数据发送,等 close() 时刷新。

根据 RealWebSocket 的 writeOneFrame() 的逻辑,在 write() 时,总是写入整个消息的所有数据,因而在 FrameSink 的 write() 中总是不会发送数据的。

writeMessageFrameSynchronized() 将用户数据格式化并发送出去。规范中定义的数据格式如下:

19956127-5a7bcae0129cb2f3

基本结构为:

  1. 第一个字节是 meta data 控制位,包括 4 位的操作码,用于指明这是否是消息的最后一帧的 FIN 位及三个保留位;
  2. 第二个字节包括掩码位,和载荷长度或载荷长度指示。只有载荷长度比较小,在 127 以内时,载荷长度才会包含在这个字节中。否则这个字节中将包含载荷长度指示的位;
  3. 可选的载荷长度。载荷长度大于 127 时,帧中会专门有一些字节来描述载荷的长度。载荷长度具体占用几个字节,因载荷的实际长度而异;
  4. 可选的掩码字节。客户端发送的帧,设置掩码指示位,并包含四个字节的掩码字节;
  5. 载荷数据。客户端发送的数据,会将原始的数据与掩码字节做异或之后再发送;

关于帧格式的更详细信息,可以参考 《WebSocket Protocol 规范》。

2.3 数据的接收

如我们前面看到的, 在握手的 HTTP 请求返回之后,会在 HTTP 请求的回调里,启动消息读取循环 loopReader():

19956127-277979bf127126bb.png

在这个循环中,不断通过 WebSocketReader 的 processNextFrame() 读取消息,直到收到了关闭连接的消息。

19956127-d429be464c4115d2.png

19956127-24da26cea5f3b1ba.png

processNextFrame() 先读取 Header 的两个字节,然后根据 Header 的信息,读取数据内容。

在读取 Header 时,读的第一个字节是同步的不计超时时间的。WebSocketReader 从 Header 中,获取到这个帧是不是消息的最后一帧,消息的类型,是否有掩码字节,保留位,帧的长度,以及掩码字节等信息。

WebSocket 通过掩码位和掩码字节来区分数据是从客户端发送给服务器的,还是服务器发送给客户端的。这里会根据协议,对这些信息进行有效性一致性检验,若不一致则会抛出 ProtocolException。

WebSocketReader 同步读取时的调用栈如下:

19956127-b0850e6e792aeb9c

通过帧的 Header 确定了是数据帧,则会执行 readMessageFrame() 读取消息帧:

19956127-6d6821cd9feecee8.png

这个过程中,会读取一条消息包含的所有数据帧。按照 WebSocket 的标准,包含用户数据的消息数据帧可以和控制帧交替发送。

但消息之间的数据帧不可以。因而在这个过程中,若遇到了控制帧,则会先读取控制帧进行处理,然后继续读取消息的数据帧,直到读取了消息的所有数据帧。

掩码位和掩码字节,对于客户端而言,发送的数据中包含这些东西,在接收的数据中不包含这些。对于服务器而言,则是在接收的数据中包含这些,发送的数据中不包含。OkHttp 既支持服务器开发,也支持客户端开发,因而可以看到对于掩码位和掩码字节完整的处理。

在一个消息读取完成之后,会通过回调 FrameCallback 将读取的内容通知出去。

19956127-1a4dbe3a24b1ce91.png

这一事件会通知到 RealWebSocket。

19956127-10635198b43b6690.png

在 RealWebSocket 中,这一事件又被通知到我们在应用程序中创建的回调 WebSocketListener。

2.4 连接的保活

连接的保活通过 PING 帧和 PONG 帧来实现。如我们前面看到的,若用户设置了 PING 帧的发送周期,在握手的 HTTP 请求返回时,消息读取循环开始前会调度 PingRunnable周期性的向服务器发送 PING 帧:

19956127-0832ca81f0b2f59c.png

在 PingRunnable 中,通过 WebSocketWriter 发送 PING 帧:

19956127-c8e041f80d41b99d.png

PING 帧是一个不包含载荷的控制帧。关于掩码位和掩码字节的设置,与消息的数据帧相同。即客户端发送的帧,设置掩码位,帧中包含掩码字节。服务器发送的帧,不设置掩码位,帧中不包含掩码字节。

通过 WebSocket 通信的双方,在收到对方发来的 PING 帧时,需要用 PONG 帧来回复。在 WebSocketReader 的 readControlFrame() 中可以看到这一点:

19956127-6c2cfa605c8b5a1f.png

PING 帧和 PONG 帧都不带载荷,控制帧读写时对于载荷长度的处理,都是为 CLOSE 帧做的。因而针对 PING 帧和 PONG 帧,除了 Header 外, readControlFrame() 实际上无需再读取任何数据,但它会将这些事件通知出去:

19956127-427c6f6a5f512ebb.png

可见在收到 PING 帧的时候,总是会发一个 PONG 帧出去,且通常其没有载荷数据。在收到一个 PONG 帧时,则通常只是记录一下,然后什么也不做。如我们前面所见,PONG 帧在 writerRunnable 中被发送出去:

19956127-eb3e4bc910e57079.png

PONG 帧的发送与 PING 帧的非常相似:

19956127-a48896eb19575cce.png

2.5 连接的关闭

连接的关闭,与数据发送的过程颇有几分相似之处。通过 WebSocket 接口的 close(int code, String reason) 我们可以关闭一个 WebSocket 连接:

19956127-f0586dcd0316179f.png

在执行关闭连接动作前,会先检查一下 close code 的有效性在合法范围内。关于不同 close code 的详细说明,可以参考 《WebSocket 协议规范》。

检查完了之后,会构造一个 Close 消息放入发送消息队列,并调度 writerRunnable 执行。Close 消息可以带有不超出 123 字节的字符串,以作为 Close message,来说明连接关闭的原因。

连接的关闭分为主动关闭和被动关闭。客户端先向服务器发送一个 CLOSE 帧,然后服务器恢复一个 CLOSE 帧,对于客户端而言,这个过程为主动关闭。反之则为对客户端而言则为被动关闭。

在 writerRunnable 执行的 writeOneFrame() 实际发送 CLOSE 帧:

19956127-20a9e3dce0898881.png

发送 CLOSE 帧也分为主动关闭的发送还是被动关闭的发送。
对于被动关闭,在发送完 CLOSE 帧之后,连接被最终关闭,因而,发送 CLOSE 帧之前,这里会停掉发送消息用的 executor。而在发送之后,则会通过 onClosed() 通知用户。

而对于主动关闭,则在发送前会调度 CancelRunnable 的执行,发送后不会通过 onClosed() 通知用户。

19956127-da163499db70e7d5.png

将 CLOSE 帧发送到网络的过程与 PING 和 PONG 帧的颇为相似,仅有的差别就是 CLOSE 帧有载荷。关于掩码位和掩码自己的规则,同样适用于 CLOSE 帧的发送。

CLOSE 的读取在 WebSocketReader 的 readControlFrame()中:

19956127-e09edb18946dac63.png

读到 CLOSE 帧时,WebSocketReader 会将这一事件通知出去:

19956127-4887b2d9cccb47e7.png

对于收到的 CLOSE 帧处理同样分为主动关闭的情况和被动关闭的情况。与 CLOSE 发送时的情形正好相反,若是主动关闭,则在收到 CLOSE 帧之后,WebSocket 连接最终断开,因而需要停掉 executor,被动关闭则暂时不需要。

收到 CLOSE 帧,总是会通过 onClosing() 将事件通知出去。

对于主动关闭的情形,最后还会通过 onClosed() 通知用户,连接已经最终关闭。

关于 WebSocket 的 CLOSE 帧的更多说明,可以参考 WebSocket 协议规范。

三、WebSocket 连接的生命周期

总结一下 WebSocket 连接的生命周期:

  1. 连接通过一个 HTTP 请求握手并建立连接。WebSocket 连接可以理解为是通过 HTTP 请求建立的普通 TCP 连接。
  2. WebSocket 做了二进制分帧。WebSocket 连接中收发的数据以帧为单位。主要有用于连接保活的控制帧 PING 和 PONG,用于用户数据发送的 MESSAGE 帧,和用于关闭连接的控制帧 CLOSE。
  3. 连接建立之后,通过 PING 帧和 PONG 帧做连接保活。
  4. 一次 send 数据,被封为一个消息,通过一个或多个 MESSAGE 帧进行发送。一个消息的帧和控制帧可以交叉发送,不同消息的帧之间不可以。
  5. WebSocket 连接的两端相互发送一个 CLOSE 帧以最终关闭连接。

关于 WebSocket 的详细信息,可以参考《 WebSocket 协议规范》。

references:

源码角度,分析OkHttp实现WebSocket---握手-保活-数据处理--- Streams 是一个 BufferedSource 和 BufferedSink 的 holder: 第三步是调用回调 onOpen()。 第四步是初始化 Reader 和 Writer: OkHttp 使用 WebSocketReader 和 WebSocketWriter 来处理数据的收发。在发送数据时将数据组织成帧,在接收数据时则进行反向擦除,同时处理 WebSocket 的控制消息。 WebSocket 的所有数据发送动作,都会在单线程线程池. 阅读详情

相关推荐

基于OKHttp的websocket封装使用

文章目录1.背景2.源码解析2.1基础封装2.2使用3.相关知识点3.1 websocket协议3.1.1、客户端:申请协议升级3.1.2、服务端:响应协议升级3.1.3、数据帧3.2 返回数据 Demo源码请点击 1.背景 一般使用到websocket协议的应用场景都是持续保持长连接,直到业务处理完毕,不再需要保持连接时,则close掉连接。那么官方给出的指导使用文档足咦。我近期工作上接到的任务...

hshuaijun55的专栏 4188

【笔记记录】使用Okhttp的WebSocket,并分析相关流程

为了了解okhttp中WebSocket的基础使用和内部调用逻辑,通过阅读相关源码熟悉内部构造和相关元素

qq_45674709的博客 3194

Web前端最全源码角度,分析OkHttp实现WebSocket---握手-保活-数据处理---,算法太TM重要了

编程基础的初级开发者,计算机科学专业的学生,以及平时没怎么利用过数据结构与算法的开发人员希望复习这些概念为下次技术面试做准备。或者想学习一些计算机科学的基本概念,以优化代码,提高编程技能。这份笔记都是可以作为参考的。开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】然而,响应到达时,尽管连接已经建立,还要为数据的收发做一些准备。这些准备中的第一步就是检查 HTTP 响应:响应码是 101;

2401_84447233的博客 1088

OkHttp实现分析之Websocket

HTML5 拥有许多引人注目的新特性,WebSocket就是其中之一。WebSocket一向有着 “Web 的 TCP ”之称。通常 WebSocket 都是用于Web的,用于构建实时的 Web 应用。它可以在浏览器和服务器之间提供一个基于 TCP 连接的双向通道。 WebSocket 协议本质上是一个基于 TCP 的协议。为了建立一个 WebSocket 连接,客户端浏览器首先要向服务器发起一个

tq08g2z的专栏 5747

测试丢包_电信IPRAN承载LTE业务丢包故障处理案例

银川 景旭阳电信IPRAN承载LTE业务丢包故障处理案例一.故障现象某地市IPRAN网络承载LTE基站业务,客户反馈近期丢包严重,基站侧ping侧核心网EPC丢包达到10%左右;且基站数量在10个左右,并分布在同一地区,需要IPRAN网络协助排查;随后查看了IPRAN网络;发现这些业务所在基站的PW-BFD历史告警存在频繁的UP/DOWN告警;综上信息展开故障处理,初步判断由于BFD频繁...

weixin_29740921的博客 1910

保姆级教程:用Dify+DeepSeek API打造你的私人股票分析助手(附完整配置流程)

本文提供了一份详细的教程,指导用户如何利用Dify低代码平台和DeepSeek API构建一个私人股票分析助手。内容涵盖从环境准备、Dify部署、DeepSeek模型配置,到设计智能体工作流和编写高效提示词的完整流程,旨在帮助投资者和开发者快速打造专属的AI投资分析工具。

weixin_29079671的博客 637

okhttp builder_源码角度,分析OkHttp实现WebSocket | 握手/保活/数据处理...

wolfcstech | 作者承香墨影 | 校对https://www.wolfcstech.com/2017/02/23/OkHttp实现分析之Websocket| 原文前段时间写了篇文章,讲解了如何使用 OkHttp 实现 WebSocket 通信,但是只停留在一些使用和理论上,分享出来各项数据还不错。本来想继续写一篇 OkHttp 关于 WebSocket 源码的分析文章。但搜索...

weixin_40002692的博客 306

[原创]Linux 802.11n CSI tool Monitor模式

Linux 802.11n CSI tool Monitor模式 使用AP模式的缺陷在于ping 命令速度比较慢,且不能精确控制发送的参数,比如接收的包数量是不可控的。Monitor模式可以调制发送速率、发包数量、发送天线个数、HT模式、short/long guard interval等等,因此调通Monitor模式是必须的。期间参考了博主沃一德的CSI Tool安装使用讲解,对他的工作表示感...

u014645508的博客 1万+

android okhttp打印请求头_源码角度,分析OkHttp实现WebSocket | 握手/保活/数据处理......

wolfcstech | 作者承香墨影 | 校对https://www.wolfcstech.com/2017/02/23/OkHttp实现分析之Websocket| 原文前段时间写了篇文章,讲解了如何使用 OkHttp 实现 WebSocket 通信,但是只停留在一些使用和理论上,分享出来各项数据还不错。本来想继续写一篇 OkHttp 关于 WebSocket 源码的分析文章。但搜索...

weixin_28716723的博客 386

FPGA之串口收发字符串之(四)——串口屏USART_HMI介绍

之前对串口各模块的设计都做了相关介绍。这里介绍串口屏的相关知识。 本次项目使用的串口屏型号是陶晶驰串口屏TJC3224T024_011,这个型号的串口屏的资料在官网可以找到。本文抛转引玉,简单介绍以便在本工程中更好的应用。 下图是该串口屏的实物图: 一般地,使用单片机或者嵌入式MCU控制串口屏,都会用到串口,同样地,在FPGA中实现也是类似,不过稍微复杂,具体代码设计过程中有以下问题需要...

隔壁old余的博客 7494

手把手教你 RT-DETR 添加注意力机制 | 一次性添加 20+ 种!

手把手教你 RT-DETR 添加注意力机制 | 一次性添加 20+ 种!

Coding... 2851

2024年最新源码角度,分析OkHttp实现WebSocket---握手-保活-数据处理---,java程序员面试常问的问题

虽然我个人也经常自嘲,十年之后要去成为外卖专员,但实际上依靠自身的努力,是能够减少三十五岁之后的焦虑的,毕竟好的架构师并不多。架构师,是我们大部分技术人的职业目标,一名好的架构师来源于机遇(公司)、个人努力(吃得苦、肯钻研)、天分(真的热爱)的三者协作的结果,实践+机遇+努力才能助你成为优秀的架构师。如果你也想成为一名好的架构师,那或许这份你需要阅读阅读,希望能够对你的职业发展有所帮助。

2401_84692429的博客 798

成本中心(CO)和利润中心(PCA)是管理会计模块的核心组件

SAP中成本中心(CO)和利润中心(PCA)凭证处理存在差异:①外部交易(如费用支付、销售)会生成FI借贷凭证;②内部成本分摊和转移仅产生CO/PCA管理凭证,通过次级成本要素或利润中心转移科目记录,不涉及FI模块。核心区别在于是否涉及企业实际收支:实际收支触发FI凭证,内部核算仅生成管理会计凭证。系统通过这种机制实现财务会计与管理会计的集成与分离。

金牌架构师 1127

okhttp实现调用websocket接口,对外再提供websocket服务

okhttp实现调用websocket接口,对外再提供websocket服务

baidu_36860454的博客 2491

基于STM32L4XX、HAL库的AD7124模数转换器ADC驱动程序设计

/ 检查ID是否正确 (AD7124-4/AD7124-8有不同的ID)// 转换为电压值 (假设使用内部2.5V基准)// 构造读命令: 1(R/W) + 1(0) + 6(寄存器地址)// 构造写命令: 0(R/W) + 1(0) + 6(寄存器地址).config = 0, // 使用配置0。内置可编程增益放大器(PGA):1-128倍。// 读取ADC数据。// 读取当前ADC控制寄存器。// 检查数据是否就绪。// 写回ADC控制寄存器。// 初始化AD7124。

zhusl6688的博客 519

AI 实战篇 |基于 AI开放平台实现 人脸识别对比 功能,超详细教程【附带源码】

本篇文章来学习一下怎样使用 Unity实现简单地人脸识别 功能。 关于人脸识别,我们可以选择很多平台的SDK接入Unity来实现人脸识别的功能。

努力前行,总会成为自己心中的那道光 5万+

OkHttp3 关于WebSocket的使用

OkHttp3 也是支持WebSocket的,因为 android 网络请求基本都用OkHttp3,所以没必要引入其他的框架了。 import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.util.Log; import androidx.annota.

qq_30894255的博客 3306

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

WebSocket——OKHttp实现

文章目录WebSocket协议概述OKHttp实现连接握手数据发送数据接收连接保活连接关闭生命周期概括 WebSocket协议概述 Webscoket是Web浏览器和服务器之间的一种全双工通信协议。比如说,服务器可以在任意时刻发送消息给浏览器。 WebSocket并不是全新的协议,而是利用了HTTP协议来建立连接。 WebSocket连接由浏览器发起,请求协议是一个标准的HTTP请求,...

PdKingLiu 1888

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

基于Okhttp下的webSocket

WebSocketManger.getInstance().initWebSocket(url):webSocket初始化,url格式ws://ip:8080。private SharedMemory createSharedMemory(byte[] data)跨进程数据传输方式:共享内存。如果在自己电脑测试,url:ws://本机ip:8080。

m0_65732353的博客 1263

聊聊OkHttp实现WebSocket细节,包括鉴权和长连接保活及其原理!

一、序 OkHttp 应该算是 Android 中使用最广泛的网络库了,我们通常会利用它来实现 HTTP 请求,但是实际上它还可以支持 WebSocket,并且使用起来还非常的便捷。 那本文就来聊聊,利用 OkHttp 实现 WebSocket 的一些细节,包括对 WebSocket 的介绍,以及在传输前如何做到鉴权、长连接保活及其原理。 二、WebSocket 简介 2.1 为什么使用 WebS...

Android 开发架构 1756

Android使用OkHttp WebSocket

什么是WebSocket WebSocket是一种在单个TCP连接上进行全双工通信的协议。它使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,客户端和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。 Websocket使用和 HTTP 相同的 TCP 端口,可以绕过大多数防火墙的限制。默认情况下,Web...

fomin 1万+

最通俗易懂的使用OkHttp进行WebSocket连接教程:上来直接撸代码

最近在项目中需要用到WebSocket来处理持续连接(persistent connection)。以前在Android端只使用过Java原生的Socket但没有使用过WebSocket,只知道OkHttp支持WebSocket。上网一搜,有些不是api太旧就是长篇大论不知所云,最终还是从国外两篇博客中得到了启发,:一篇是通过例子直接介绍使用,我决定先把这篇博客分享给大家,直接上手;另一...

xlh1191860939的博客 4万+

OkHttp中的Socket连接

Java网络连接超底层分析 看完这篇博客,感觉网络请求框架自己都可以撸一个。 OSI网络模型 TCP/IP模型 物理层 数据链路层 网络连接层 网络层 网际层 传输层 传输层 会话层 表示层 应用层 应用层 这个源码分析,感觉不会超过网络上大神的分享,但是还是要写份自己的。 先说说这个OKHttp请求的需要...

厚德出品,必是精品 9710
上一篇: 阿里P10赵海平跳槽字节跳动:深度解析跳槽从开始到结束完整流程!
下一篇: 高频Flutter 问题大汇总,总有一款曾困惑你!(含解决问题方法)
Python_林一
博客等级 码龄7年 877粉丝 510原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值