42

.NET斗鱼直播弹幕客户端(上)

 4 years ago
source link: https://www.tuicool.com/articles/VJB7biA
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

前言

现在直播平台由于 弹幕 的存在,主播与观众可以更轻松地进行互动,非常受年轻群众的欢迎。斗鱼TV就是一款非常流行的直播平台,弹幕更是非常火爆。看到有不少主播接入 弹幕语音播报器弹幕点歌 等模块,这都需要首先连接斗鱼弹幕。

经常看到其它编程语言的开发者,分享了他们斗鱼弹幕客户端的代码。 .NET 当然也能做,还能做得更好(只是不知为何很少见人分享:joy:)。

本文将包含以下内容:

  1. 我将使用斗鱼TV官方公开的弹幕PDF文档,使用  SocketTcpClient 连续斗鱼弹幕;

  2. 分析如何利用  .NET 强大的  ValueTask 特性,在保持代码简洁的同时,轻松享受高性能异步代码的快乐;

  3. 然后将使用  ReactiveExtensions (  RX ),演示如何将一系列复杂的弹幕接入操作,就像写  HelloWorld 一般容易;

  4. 用我自制的“准游戏引擎”  FlysEngine ,只需少量代码,即可将斗鱼TV的弹幕显示左右飞过的效果;

本文内容可能比较多,因此分上、下两篇阐述,上篇将具体聊聊第1、2点,第3、4点将在下篇进行,整篇完成后,最终效果如下:

yemeqy6.gif

斗鱼直播API

现在网上可以轻松找到 斗鱼弹幕服务器第三方接入协议v1.6.2.pdf (网上搜索该关键字即可找到)。文档提到,第三方接入弹幕服务的服务器为 openbarrage.douyutv.com:8601 ,我们可以使用 TcpClient 来方便连接:

该文档中提到所有数据包格式如下:

mEjyYbY.png!web

注意前两个4字节的消息长度是完全一样的,可以使用 Debug.Assert 进行断言。

其中所有数字都为小端整数,刚好 .NETBinaryWriter 类默认都以小端整数进行转换。可以利用起来。

因此,读取一个消息包的完整代码如下:

其中 bytes 既是数据部分,根据 pdf 文档中的规定,该部分为 UTF-8 编码,在 C# 中使用 Encoding.UTF8.GetString() 即可获取其字符串,该字符串长这样子:

该格式不是 JSON / XML 等,但仔细分析又确实有逻辑,有层次感,根据文档,该格式为所谓的 STT 序列化,该格式包含键值对、数组等多种格式。虽然不懂为什么不用 JSON 。还好协议简单,我可以通过寥寥几行代码,即可转换为 Json.NETJToken 格式:

这样一来,即可将 STT 格式转换为 JSON 格式,因此只需像 JSON 格式取出 nn 字段和 txt 字段即可,还有一个 col 字段,可以用来确定弹幕颜色,我可以将其转换为 RGBint32 值:

该代码使用了 C# 8.0switchexpression 功能,可以一个表达式转成整个颜色转换,比 if/elseswitch/case 语句都精简不少,可谓一气呵成。

支持异步/ ValueTaskMemory<T> 优化

C# 5.0 提供了强大的异步 API —— async/await ,通过异步API,以前难以用编程实现的操作现在可以像写串行代码一样轻松完成,还能轻松加入取消任务操作。

然后 C# 7.0 发布了 ValueTaskValueTask 是值类型,因此在频繁调用异步操作(如使用 Stream 读取字节)时,不会因为创建过多的 Task 而分配没必要的内存。这里,我确实是使用 TCP 连接流读取字节,是使用 ValueTask 的最佳时机。

这里我们将尝试将代码切换为 ValueTask 版本。

首先第一个问题是 BinaryReader 类,该类提供了便利的字节操作方式,且能确保字节端为小端,但该类不提供异步 API ,因此需要作一些特殊处理:

如代码所示,我封装了 ReadInt16()ReadInt32() 两个方法,

如图,我还使用了一个 while 语句,因为不像 BinaryReader ,如果一次无法读取所需的字节数(4个字节), stream.ReadAsync() 并不会堵塞线程。然后需要将 int32Buffer 转换为 int 类型。

注意:此处我没有使用 BitConverter.ToInt32() ,也不能使用该方法,因为该方法不像 BinaryReader ,它在大端/小端的 CPU 上会有不同的行为。(其中在大端 CPU 上将有错误的行为)涉及二进制序列化需要传输的,不能使用 BitConverter 类。

同样的,写 TCP 流也需要有相应的变化:

总结

最终运行效果如下:

Evm2mqm.gif

这一篇【DotNet骚操作】文章介绍了如何使用斗鱼tv开放弹幕 API ,下篇将会:

  • 共享本文所使用的所有完整的源代码;

  • 介绍如何使用  ReactiveExtensions (  RX ),演示这一系列操作用起来,就像写  HelloWorld 一样简单;

  • 用我自制的“准游戏引擎”  FlysEngine ,只需少量代码,即可实现桌面弹幕的效果;

敬请期待!“刷一波666:rocket::rocket::rocket:”

b2Q7ryq.jpg!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK