/// <summary> /// 开启连接 /// </summary> /// <returns></returns> public async Task <bool> ConnectAsync() { _roomId = await RoomUtil.GetLongRoomId(_shotRoomId); if (_roomId == 0) { return(false); } var token = await RoomUtil.GetRoomTokenByShortRoomId(_shotRoomId); if (token.Equals("")) { return(false); } if (!await RoomUtil.ConnectRoomByShortRoomId(_tcpClient, _shotRoomId)) { return(false); } _roomStream = _tcpClient.GetStream(); if (!await SendJoinMsgAsync(token)) { //这是错误处理的代码 return(false); } var headBuffer = new byte[ProtocolHeadLength]; await _roomStream.ReadAsync(headBuffer, 0, headBuffer.Length); DanmuHead danmuHead = DanmuHead.BufferToDanmuHead(headBuffer); if (danmuHead.HeaderLength != ProtocolHeadLength || danmuHead.Action != 8) { //如果头信息的长度不是16,或者Action的的值不是8 (服务器接受认证包后回应的第一个数据) //这是错误处理的代码 return(false); } var dataBuffer = new byte[danmuHead.PacketLength - danmuHead.HeaderLength]; await _roomStream.ReadAsync(dataBuffer, 0, danmuHead.MessageLength()); var s = Encoding.Default.GetString(dataBuffer); var data = JObject.Parse(s); if (int.Parse(data["code"].ToString()) != 0) { return(false); } _connected = true; //循环发送心跳信息 #pragma warning disable 4014 SendHeartbeatLoop(); #pragma warning restore 4014 return(true); }
/// <summary> /// 循环读取消息,禁止重复调用 /// </summary> /// <returns></returns> public async Task ReadMessageLoop() { while (_connected) { var headBuffer = new byte[ProtocolHeadLength]; //先读取一次头信息 await _roomStream.ReadAsync(headBuffer, 0, ProtocolHeadLength); //解析头信息 DanmuHead danmuHead = DanmuHead.BufferToDanmuHead(headBuffer); //判断协议 if (danmuHead.HeaderLength != ProtocolHeadLength) { continue; } //初始化一个放数据的byte数组 byte[] dataBuffer; if (danmuHead.Action == 3) { //给服务器发送心跳信息后的回应信息,所带的数据是直播间的观看人数(人气值) dataBuffer = new byte[danmuHead.MessageLength()]; await _roomStream.ReadAsync(dataBuffer, 0, danmuHead.MessageLength()); var audiences = EndianBitConverter.EndianBitConverter.BigEndian.ToInt32(dataBuffer, 0); _messageHandler.AudiencesHandlerAsync(audiences); continue; } string tmpData; JObject json = null; if (danmuHead.Action == 5 && danmuHead.Version == ProtocolVersion) { //有效负载为礼物、弹幕、公告等内容数据 //读取数据放入缓冲区 dataBuffer = new byte[danmuHead.MessageLength()]; await _roomStream.ReadAsync(dataBuffer, 0, danmuHead.MessageLength()); //之后把数据放入到内存流 string jsonStr; using (var ms = new MemoryStream(dataBuffer, 2, danmuHead.MessageLength() - 2)) { //使用内存流生成解压流(压缩流) var deflate = new DeflateStream(ms, CompressionMode.Decompress); var headerbuffer = new byte[ProtocolHeadLength]; try { while (true) { await deflate.ReadAsync(headerbuffer, 0, ProtocolHeadLength); danmuHead = DanmuHead.BufferToDanmuHead(headerbuffer); var messageBuffer = new byte[danmuHead.MessageLength()]; var readLength = await deflate.ReadAsync(messageBuffer, 0, danmuHead.MessageLength()); jsonStr = Encoding.UTF8.GetString(messageBuffer, 0, danmuHead.MessageLength()); if (readLength == 0) { break; } json = JObject.Parse(jsonStr); _messageDispatcher.DispatchAsync(json, _messageHandler); } continue; } catch (Exception e) { //读数据超出长度 Debug.WriteLine(e); throw; } } } dataBuffer = new byte[danmuHead.MessageLength()]; await _roomStream.ReadAsync(dataBuffer, 0, danmuHead.MessageLength()); tmpData = Encoding.UTF8.GetString(dataBuffer); try { json = JObject.Parse(tmpData); } catch (Exception e) { Debug.WriteLine(e); throw e; } if (!"DANMU_MSG".Equals(json["cmd"].ToString()) && !"SEND_GIFT".Equals(json["cmd"].ToString())) { _messageDispatcher.DispatchAsync(json, _messageHandler); } } }
/// <summary> /// 开启连接 /// </summary> /// <returns></returns> public async Task <bool> ConnectAsync() { var tmpData = JObject.Parse( await _httpClient.GetStringAsync( $"https://api.live.bilibili.com/room/v1/Room/room_init?id={_shotRoomId}")); if (int.Parse(tmpData["code"].ToString()) != 0) { return(false); } _roomId = int.Parse(tmpData["data"]["room_id"].ToString()); tmpData = JObject.Parse(await _httpClient.GetStringAsync( $"https://api.live.bilibili.com/room/v1/Danmu/getConf?room_id={_roomId}&platform=pc&player=web")); //连接的令牌 var token = tmpData["data"]["token"].ToString(); //解析域名,拿取IP地址,用于连接 var chatHost = tmpData["data"]["host"].ToString(); var ips = await Dns.GetHostAddressesAsync(chatHost); //连接的端口 var chatPort = int.Parse(tmpData["data"]["port"].ToString()); Random random = new Random(); //随机一个选择域名解析出来的IP,负载均衡 await _tcpClient.ConnectAsync(ips[random.Next(ips.Length)], chatPort); if (!_tcpClient.Connected) { //这是错误处理的代码 return(false); } _roomStream = _tcpClient.GetStream(); //判断能不能写入数据 if (!_roomStream.CanWrite) { //这是错误处理的代码 return(false); } if (!await SendJoinMsgAsync(token)) { //这是错误处理的代码 return(false); } var headBuffer = new byte[ProtocolHeadLength]; await _roomStream.ReadAsync(headBuffer, 0, headBuffer.Length); DanmuHead danmuHead = DanmuHead.BufferToDanmuHead(headBuffer); if (danmuHead.HeaderLength != ProtocolHeadLength || danmuHead.Action != 8) { //如果头信息的长度不是16,或者Action的的值不是8 (服务器接受认证包后回应的第一个数据) //这是错误处理的代码 return(false); } var dataBuffer = new byte[danmuHead.PacketLength - danmuHead.HeaderLength]; await _roomStream.ReadAsync(dataBuffer, 0, danmuHead.MessageLength()); var s = Encoding.Default.GetString(dataBuffer); var data = JObject.Parse(s); if (int.Parse(data["code"].ToString()) != 0) { return(false); } _connected = true; //循环发送心跳信息 #pragma warning disable 4014 SendHeartbeatLoop(); #pragma warning restore 4014 return(true); }