/// <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);
                }
            }
        }
Exemple #3
0
        /// <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);
        }