我欢迎所有对此协议感兴趣的人,并在此先对我的过分感动表示歉意。 仓促地(必要时)从事此主题,但时间很长。 在这方面,已经积累并形成了设计和使用该技术的某种实践。
这里描述
了服务实现选项。 从那以后,大量的水流了出来。 基本原理保持不变,但是应用程序本身的代码已进行了自然修改。 在某些地方,发现并解决了非严重错误,在某些地方对程序流,打开的连接列表等进行了优化。
如您所知,除了服务器端,还有客户端。 在这里,我想更彻底地停下来,描述我必须面对的事情以及可能受到的影响。 当然,在使用JavaScript时,您将无法进行“嬉戏”,因为一切都准备就绪且已关闭,但是您可以对Java客户端有所了解。
不管您多么优秀的程序员,总是很难开发,发明独特的东西然后调试自己的经文。 因此,一次我屈服于寻找已经准备好的东西的诱惑,使您可以立即在我的项目中使用它。 完成模块的选择标准很简单。 我想以最小的开销获得Java完整,有效的代码。
作为选定的对象,我选择了使用Apache库的模块。 特别是这些:
- apache-mime4j-core-0.7.2.jar;
- httpclient-4.2.1.jar;
- httpcore-4.2.1.jar;
- httpmime-4.2.1.jar。
关于它们的使用可以说些什么? Apache软件一直以其可靠性,复杂性和最佳性而闻名。 Android客户端成功运行。 完成的* .apk文件的大小不是非常大。 对于这些图书馆的工作没有特别的抱怨。 但是生活总是比我们聪明。 时间(此期间大约为四到五年)会自行调整。 该应用是在有Android 4.2-4.4版本时编写的。 今年,当版本10的设备已经全面投入使用时,对新解决方案的需求已经出现。
该开发当时是在Eclipse for Windows 7上进行的。将Android SDK更新到所需级别会导致一个事实,即128 GB的小型SSD硬盘已满。 我不得不切换到Android Studio。 此外,我不得不更改基本操作系统。 我尝试安装Ubuntu(我不记得版本号)并已在此环境中使用Studio。 但是再次失败,Andriod Studio固执地不想安装。
为什么-已经忘记了。 最后,在朋友的建议下,他安装了最新版本的Linux-Mint,瞧瞧,该工具包就毫无疑问地放在了它上。 然后实际发生了什么,正是由于这些原因,描述了所有这些细节,即编写测试的例程。
那么,这种激肽激素的预期结果是什么? 让我们从一个事实开始,Apache从官方站点复制了上述库的更多当前版本。 将它们添加到项目中,然后...出现编译错误。 时间已过去,类接口已更改。 因此,我不得不(由于缺乏时间来研究新库)回到旧版本。 但是...
但是话又说回来,我们不是在寻找简单的方法。 我想,为什么我完全需要这些库? 这些软件包的文本是。 如果您仅从他们那里选修必要的课程怎么办? 此外,在考虑用于Web套接字的模块的文本时,您只能从这些库中看到两个类。
因此,我创建了一个新项目,并开始添加必要的类。 最后,结果证明,要成功进行编译,必须提取32个类。 但是,是的,该项目成功了。 一切都在呼吸。 与Web套接字服务的连接成功。 一切都会好起来的,但是注意到了以下事件,这对我来说是不可理解的。 关闭连接时,负责连接的模块引发异常:
java.io.EOFException
在java.io.DataInputStream.readByte(DataInputStream.java:77)
在com.example.wsci.HybiParser.start(HybiParser.java:112)
在com.example.wsci.WebSocketClient $ 1.运行(WebSocketClient.java:144)
在java.lang.Thread.run(Thread.java:818)
我很茫然。 以下感到困惑。 与服务器的连接成功。 包成功地来了。 但是,为什么闭包到底会引发异常? 而且,所有内容在服务器上都是标准的。 显然,在案文的某个地方,客户有一些琐事影响了结帐。 而且,文本显示了这种特征。 根据
文档的第7.1.1节,在客户端进行关闭不仅包括调用close()方法,还包括形成并发送操作码为8的数据包(关闭操作)。 在这种情况下,服务器将发送其关闭数据包,然后客户端将关闭连接。 但是在我们的情况下,未观察到这样的调用顺序。 它只是称为关闭函数而已。 总的来说,有些事情要考虑。 而且,我越用分组解析器浏览和研究该模块的文本,就越不喜欢它,我就越渴望用我对这个协议的看法来重写它们。 最后,决定执行这一“劳动壮举”。
究竟是什么不合适,是什么导致了这些模块中的“公民抗议”? 首先,与服务器直接连接的模块与数据包解析器之间的交互组织。 事实证明,连接模块与服务器进行了交互,生成了一个解析器,并向该解析器传递了指向自身的链接作为参数。 结果,解析器被授权对即将发生的网络事件做出决策。 在这方面,出现了问题,但这很好吗? 如果解析器模块能够完成其各自的任务,返回其工作结果,但是对事件的控制决定将由生成解析器的对象执行,那会更好吗? 在这种情况下,将确定对象之间交互的严格层次结构。 (当然,您可以在这里辩论哪种方法更好-层次结构或网络,但是我们不再讨论该主题。)
使我想重写所有内容的第二件事是解析器的结构。 该对象(类)应实现两个主要功能,即形成一个数据包以传输到服务器,以及解析从服务器接收到的数据包。 因此,基本上这两个功能不合适。 这就是事情。
想象发生了网络事件,数据包已经到达。 HybiParser在这种情况下做了什么? 此对象按字节从套接字的输入流中读取前两个字节,并确定其下一步操作:解析数据大小,掩码等。 结果,这是通过从套接字的输入流进行的几次读取操作实现的。 而且,读取阶段使解析变得复杂,从而使算法更加复杂。 再次出现问题,是对的,为什么会有这样的困难? 将数据包视为一项操作是否更好,特别是因为可以确定传入数据的大小?
第三。 解析器工作中另一个有争议的方面似乎是“永恒”的数据包接受周期。 该循环在单独的程序流中运行。 在某个时候,插座关闭。 接下来,通常的异常处理是什么? 还是该怎么办? 不,我不反对例外机制,但是很高兴预见这种情况以及对此的反应。 例如,可以提出一种同步机制作为解决方案,在此期间,将定期完成循环,并因此发生程序流。
通过评估所有这些细微差别,确定了必要模块设计的以下要求:
- 模块必须独立于第三方库;
- 模块应该简单易用,可以集成到其他项目中;
- 模块应该为将来的功能扩展做好准备。
好吧,为了不因对以前的现成解决方案的过度批评而受到指责,我们还补充说,现成的和非批评性功能的一部分可以安全地转移到新的实现中。 好的,就是这样,正如他们在苏共第二十二届代表大会上所说:“我们的目标很明确,任务已经定义。 同志们,上班! 为了共产主义的新胜利!”
总的来说,亲爱的读者们,为了不给您造成负担,也不浪费您的宝贵时间,我将简要介绍我的建议,仅关注重点。
因此,建议的实现仅包含四个模块(根据Apache库的上述要求或项目中未包含其中的单个类):
- WebSocket协议07全局常量模块;
- 助手异常类;
- Web套接字客户端;
- 用于解析WebSocket协议级别07的数据包的模块。
在前两个模块中,实现很简单,没有什么可考虑的。 客户端模块实现了对与服务器的连接的控制,我想在以下几点进行介绍。 连接打开功能具有来自服务器的标头循环。 在这里,实际上实现了Sec-WebSocket-Accept密钥解析,在我们的示例中,解析是在不使用Apache库的情况下执行的。
接下来,请注意数据包循环控制功能。 通过同步对象,实现很简单。
下一个要注意的点是循环的功能。 循环不是“永恒的”,而是在检查同步对象的情况下退出。 一个周期内,一个操作中读取到达的数据包。 该包由相应的对象解析以进行解析。 接下来,对即将发生的网络事件做出管理决策。
为了完成描述,我们注意安全连接终止的功能。 这样做如下。 将连接终止数据包发送到服务器,并生成Runnable类的变量,然后将其放入队列处理器中,以通过postDelayed函数执行,该函数的参数之一是毫秒级的操作延迟。 在Runnable变量中,当程序流结束并且与服务器的连接关闭时,运行函数包含一系列调用。 如果关闭响应数据包提前到达,则删除处理列表中的该位置。
实现WebSocket数据包分析的类包含两种需要注意的方法:解析自身和根据相关参数形成用于传输的数据包。 解析时,接收到的数据包中的所有标志和数据都存储在公共的类变量中。 为什么公开? 是的,为简单起见,以免为它们创建其他的get / set函数。
好吧,实际上,亲爱的读者。 随附带有Android Studio项目的存档。 我不会对在您的项目中使用这些文本提出任何要求。 建设性的批评被接受。 尽可能回答问题。