{
"title": "B站直播弹幕ws协议分析",
"tags": [
"post",
"技术"
],
"sources": [
"xlog"
],
"external_urls": [
"https://daidr.xlog.app/bilibili-live-danmuku"
],
"date_published": "2019-10-06T14:02:00.000Z",
"content": "\n![image](ipfs://bafkreicbpdjqrx2tp5eoqdqghswygh7l2z4uuovbme3upz6lsnwfwqcpu4)\n\n\n> Chrome DevTools可以直接查看binary类型数据包了!\n\n## 连接\n\n通过Chrome DevTools可以看到,网页版B站直播的弹幕通过 `wss://tx-sh3-live-comet-04.chat.bilibili.com/sub` 传输,这个地址每次是不一样的。需要通过 `https://api.live.bilibili.com/room/v1/Danmu/getConf?room_id=房间号&platform=pc&player=web` 获得wss地址(应该是负载均衡的需要,实际测试连接任意wss地址都能正常获取弹幕)\n\n封包头部16个字节用于标识数据包的长度及类型,数据包格式详见下表。字节序均为大端模式。参考:https://blog.csdn.net/xfgryujk/article/details/80306776\n\n| 偏移 | 长度 | 类型 | 含义 |\n|---------|------|------|------|\n|\t0\t\t|\t4\t|\tint\t|\t数据包长度\t|\n|\t4\t\t|\t2\t|\tint\t|\t数据包头部长度,固定为 16\t|\n|\t6\t\t|\t2\t|\tint\t|\t数据包协议版本(见下文)\t|\n|\t8\t\t|\t4\t|\tint\t|\t数据包类型 (见下文)\t|\n|\t12\t|\t4\t|\tint\t|\t固定为 1\t|\n|\t16\t|\t–\t|\tbyte[]\t|\t数据主体\t|\n\n|\t数据包协议版本\t|\t含义\t|\n|-|-|\n|0\t|数据包有效负载为未压缩的JSON格式数据|\n|1\t|客户端心跳包,或服务器心跳回应(带有人气值)|\n|2\t|数据包有效负载为通过zlib压缩后的JSON格式数据|\n\n客户端建立连接后,需要在5秒内发出加入房间(认证)的数据包,否则会被服务器强制断开连接。其中有效负载的key字段内容可以从之前的 `https://api.live.bilibili.com/room/v1/Danmu/getConf?room_id=房间号&platform=pc&player=web` 获取。如发送的认证包格式错误,服务器会立刻强制断开连接,JSON字段的详细说明见下表。\n\n![image](ipfs://bafkreids7pvx6dqxxr7lyfrvm7ubcw76sq5xy7aenq52vypdikrpmsquhe)\n\n| 字段 | 类型 | 必选 | 含义 |\n| --- | --- | --- | --- |\n| uid | number | × | 用户UID |\n| roomid | number | √ | 房间号 |\n| protover | number | × | 协议版本,目前为 2 |\n| platform | string | × | 平台,可以是 web |\n| clientver | string | × | 客户端版本,可以是 “1.8.5” |\n| type | number | × | 未知,可以是 2 |\n| key | string | × | 用户标识,通过之前提到的接口获取 |\n\n## 心跳\n\n心跳包建议每30秒发一次,头部16字节遵守上文规则,负载内容随意。(b站通过传入一个空对象来生成心跳包,然后就有了我之前无法理解的心跳包内容)\n\n![image](ipfs://bafkreidblrf2cptvsjeagyzxlao533k4sxp6sixscxray42ipgwqqtx7nm)\n\n## 通知(弹幕、公告、礼物等)\n\n有新的弹幕、礼物或其他公告时,服务器会发送类似下图的数据包,首先需要使用 `zlib.inflate` 解压数据主体部分(除头部16字节外)。解压后的数据头部十六字节与原数据头相同,去除头部后即为JSON格式数据\n\n这里我们以一个弹幕数据包为例子\n\n![image](ipfs://bafybeic3rehm7n5nfjuwqp2b2ypwuz2tavtpbpgypnbh62igrsvhuz4g4u)\n\n![image](ipfs://bafybeiad6c7jgld2do6b4yeet4g6jcvejlg6h3daukxudhnw5ndazegbdq)\n\n可以看到解压后的数据依然带有头部(16字节),去除头部后即为JSON格式数据,其中的cmd字段更为详细地描述了数据包类型。其中比较明显的是,`['info'][1]` 代表弹幕内容, `['info'][2][1]` 为发送者,`['info'][9]['ts']` 为发送时间戳,cmd的已知格式参考下表\n\n| cmd字段 | 含义 |\n| --- | --- |\n| DANMU\\_MSG | 收到弹幕 |\n| SEND\\_GIFT | 有人送礼 |\n| WELCOME | 欢迎加入房间 |\n| WELCOME\\_GUARD | 欢迎房管加入房间 |\n| SYS\\_MSG | 系统消息 |\n| PREPARING | 主播准备中 |\n| LIVE | 直播开始 |\n\n下面我展示了几个常见cmd的数据包JSON格式,还有很多活动通知cmd,各位可以自行抓取(如下面的 `ACTIVITY_BANNER_UPDATE_V2` 就是我写文章当天出现的活动通知cmd类型)\n\n```json\n{\n \"cmd\": \"SEND_GIFT\",\n \"data\": {\n \"giftName\": \"辣条\",\n \"num\": 5,\n \"uname\": \"迪多玛索\",\n \"face\": \"http://i2.hdslb.com/bfs/face/1a3b795aafc5887f3f33909c7e66876d23911979.jpg\",\n \"guard_level\": 0,\n \"rcost\": 42593386,\n \"uid\": 415822879,\n \"top_list\": [],\n \"timestamp\": 1570368091,\n \"giftId\": 1,\n \"giftType\": 0,\n \"action\": \"喂食\",\n \"super\": 0,\n \"super_gift_num\": 0,\n \"price\": 100,\n \"rnd\": \"EF27025C-4C20-440F-B36F-64CCFABBF68E\",\n \"newMedal\": 0,\n \"newTitle\": 0,\n \"medal\": [],\n \"title\": \"\",\n \"beatId\": \"\",\n \"biz_source\": \"live\",\n \"metadata\": \"\",\n \"remain\": 0,\n \"gold\": 0,\n \"silver\": 0,\n \"eventScore\": 0,\n \"eventNum\": 0,\n \"smalltv_msg\": [],\n \"specialGift\": null,\n \"notice_msg\": [],\n \"capsule\": null,\n \"addFollow\": 0,\n \"effect_block\": 1,\n \"coin_type\": \"silver\",\n \"total_coin\": 500,\n \"effect\": 0,\n \"broadcast_id\": 0,\n \"draw\": 0,\n \"crit_prob\": 0,\n \"tag_image\": \"\",\n \"user_count\": 0,\n \"send_master\": null\n }\n}\n```\n\n```json\n{\n \"cmd\": \"ACTIVITY_BANNER_UPDATE_V2\",\n \"data\": {\n \"id\": 378,\n \"title\": \"第6名\",\n \"cover\": \"\",\n \"background\": \"https://i0.hdslb.com/bfs/activity-plat/static/20190904/b5e210ef68e55c042f407870de28894b/14vZu7h9pK.png\",\n \"jump_url\": \"https://live.bilibili.com/p/html/live-app-rankcurrent/index.html?is_live_half_webview=1&hybrid_half_ui=1,5,85p,70p,FFE293,0,30,100,10;2,2,320,100p,FFE293,0,30,100,0;4,2,320,100p,FFE293,0,30,100,0;6,5,65p,60p,FFE293,0,30,100,10;5,5,55p,60p,FFE293,0,30,100,10;3,5,85p,70p,FFE293,0,30,100,10;7,5,65p,60p,FFE293,0,30,100,10;&anchor_uid=22550271&is_new_rank_container=1&area_v2_id=163&area_v2_parent_id=3&rank_type=master_realtime_area_hour&area_hour=1\",\n \"title_color\": \"#8B5817\",\n \"closeable\": 1,\n \"banner_type\": 4,\n \"weight\": 18,\n \"add_banner\": 0\n }\n}\n```\n\n```json\n{\n \"cmd\": \"ROOM_REAL_TIME_MESSAGE_UPDATE\",\n \"data\": {\n \"roomid\": 101526,\n \"fans\": 294665,\n \"red_notice\": -1\n }\n}\n```\n\n> 后记:Chrome支持直接显示WebSocket二进制包真的能节省很多时间。吹爆 Chrome!",
"attributes": [
{
"value": "bilibili-live-danmuku",
"trait_type": "xlog_slug"
}
]
}