写在前面
最近由于自己在B站直播的原因,对B站本身提供的实时弹幕不太满意,于是自己抓包写了一个bilibili的弹幕协议,但还有一部分没有完成。留下的坑以后再慢慢填吧。
socket包获拦截工具:Wireshark
demo实现语言环境:C#
抓取过程
1、获取直播间的ROOM_ID
bilibili的直播房间的URL是形如:http://live.bilibili.com/180 类型的
但和其他直播网站不同的是180是临时分配的房间号
查看网页源码,在头文件中可以找到:
<head>
<!-- 省略 -->
<script>
var ROOMID = 98284;
var DANMU_RND = 1479304877;
var NEED_VIDEO = 1;
var ROOMURL = 180;
var INITTIME = Date.now();
</script>
<!-- 省略 -->
</head>
获取对应:
ROOMID位真实房间号
DANMU_RND推测应该是用户登录的分配随机数
2、wireshark解析
通过简单的网页流量监控能够找出bilibili弹幕服务器的IP地址
可以看出目标主机的IP是:183.147.212.11 端口号为788
紧接着使用wirshark抓包
设置拦截条件为
tcp.port==788 && ip.addr==183.147.212.11
进入直播间分析数据:
PSH,ACK 端口为788
解析数据
0000 00 00 00 3d 00 10 00 01 00 00 00 07 00 00 00 01 ...=............
0010 7b 22 72 6f 6f 6d 69 64 22 3a 31 31 38 32 37 35 {"roomid":118275
0020 36 2c 22 75 69 64 22 3a 37 36 39 34 32 36 32 2c 6,"uid":7694262,
0030 22 70 72 6f 74 6f 76 65 72 22 3a 32 7d "protover":2}
得出部分有用信息:
0x3d 数据长度
0x07 进入直播间
后面一部分按照正常方式解析为就可以
心跳包解析:
由于采用TCP/IP协议,通过wireshark发现每隔一段时间都会固定向183.147.212.11 788 发送一个固定大小为70的封包
取出其中data部分
0000 00 00 00 10 00 10 00 01 00 00 00 02 00 00 00 01 ................
格式和数据都固定,知道每隔30s发送一个包就可以维持心跳了
紧接着解析收到的心跳内容
0000 00 00 00 14 00 10 00 01 00 00 00 03 00 00 00 01 ................
0010 00 00 00 03 ....
开头格式 0x00 0x00 0x00 0x14固定,可以用来判断是否为心跳包
第一个0x03是心跳标志
最后的 0x0003 是当前房间的人数
弹幕数据:
每当有数据来的时候
很容易解析
0000 00 00 00 b9 00 10 00 00 00 00 00 05 00 00 00 00 ................
0010 7b 22 69 6e 66 6f 22 3a 5b 5b 30 2c 31 2c 32 35 {"info":[[0,1,25
0020 2c 31 36 37 37 37 32 31 35 2c 31 34 37 39 33 30 ,16777215,147930
0030 37 39 30 35 2c 2d 32 37 39 30 33 35 33 39 36 2c 7905,-279035396,
0040 30 2c 22 39 37 64 37 65 34 31 38 22 2c 30 5d 2c 0,"97d7e418",0],
0050 22 73 73 73 73 22 2c 5b 37 36 39 34 32 36 32 2c "ssss",[7694262,
0060 22 e8 bd af e8 82 9a e5 ad 90 e7 9a 84 e7 8b 90 "...............
0070 e7 8b b8 22 2c 31 2c 31 2c 30 2c 31 30 30 30 30 ...",1,1,0,10000
0080 2c 31 5d 2c 5b 5d 2c 5b 32 30 2c 30 2c 36 32 31 ,1],[],[20,0,621
0090 35 36 37 39 2c 22 3e 35 30 30 30 30 22 5d 2c 5b 5679,">50000"],[
00a0 5d 2c 30 2c 30 5d 2c 22 63 6d 64 22 3a 22 44 41 ],0,0],"cmd":"DA
00b0 4e 4d 55 5f 4d 53 47 22 7d NMU_MSG"}
其中的内容分析:
0,1,25标准格式不清楚
16777215为当前登录ID
1479307905为前方分析的DANMU_RND
“97d7e418”不清楚
"ssss"为弹幕内容
7694262为用户ID
“...”没能显示的为用户姓名
1,1,0分别对应 admin,vip,svip
后面的内容没有做分析
这里给出我分析出来的弹幕命令
{"info":[[0,1,25,16777215,1478145019,1098959490,0,"73dec35f",0],"初二物理",[11911154,"Asysika",0,0,0,10000],[],[2,0,16754085,">50000"],[],0,0],"cmd":"DANMU_MSG"}
{"cmd":"WELCOME","data":{"uid":3966619,"uname":"\u5c0f\u68a6\u306e\u7ae0\u9c7c\u54e5","isadmin":1,"svip":1}
{"cmd":"SEND_GIFT","data":{"giftName":"233","num":1,"uname":"\u5c0f\u68a6\u306e\u7ae0\u9c7c\u54e5","rcost":121841,"uid":3966619,"top_list":[{"uid":3966619,"uname":"\u5c0f\u68a6\u306e\u7ae0\u9c7c\u54e5","coin":1440977,"guard_level":0}
{"uid":3966619,"uname":"\u5c0f\u68a6\u306e\u7ae0\u9c7c\u54e5","coin":1440045,"guard_level":0}
{"info":[[0,1,25,16777215,1478149142,2130510810,0,"8f533746",0],"下播了吗",[24614852,"溟孜沐",0,0,0,10000],[3,"梦宝","阿梦小盆友",1275151,7722635],[18,0,6215679,">50000"],["title-56-1","title-56-1"],0,0],"cmd":"DANMU_MSG"}
{"cmd":"SYS_MSG","msg":"\u3010\u821e\u6cd5\u5929\u5973\u75f4\u6c49\u5f03\u3011:?\u5728\u76f4\u64ad\u95f4:?\u3010187\u3011:?\u8d60\u9001 \u5c0f\u7535\u89c6\u4e00\u4e2a\uff0c\u8bf7\u524d\u5f80\u62bd\u5956","rep":1,"styleType":2,"url":"http:\/U_MSG"}
其中的TCP封包存在被分割的情况,读取的话socket不要设置为拥塞模式
在这里做了一个小的demo演示,支持弹幕点歌,但是还没有完善,有兴趣的同学可以帮我把坑填上
结语
因为自身的局限,任然有一部分的信息没有分析出来,也希望有志同道合的朋友一起把弹幕协议完善。