/// <summary>
        /// 清楚订阅的离线客户端
        /// </summary>
        /// <param name="channel">订阅名称</param>
        public void ClearChannelClient(string channel)
        {
            string channelKey   = RedisKeyFormatUtil.GetSubscribeChannelKey(_appId, channel);
            var    websocketIds = _redis.HKeys(channelKey);
            var    offline      = new List <string>();
            var    span         = websocketIds.AsSpan();
            var    start        = span.Length;

            while (start > 0)
            {
                start = start - 10;
                var length = 10;
                if (start < 0)
                {
                    length = start + 10;
                    start  = 0;
                }
                var    slice     = span.Slice(start, length);
                string onlineKey = RedisKeyFormatUtil.GetOnLineClientKey(_appId);
                var    hvals     = _redis.HMGet(onlineKey, slice.ToArray().Select(b => b.ToString()).ToArray());
                for (var a = length - 1; a >= 0; a--)
                {
                    if (string.IsNullOrEmpty(hvals[a]))
                    {
                        offline.Add(span[start + a]);
                        span[start + a] = null;
                    }
                }
            }
            //删除离线订阅
            if (offline.Any())
            {
                _redis.HDel(channelKey, offline.ToArray());
            }
        }
        /// <summary>
        /// 发送订阅消息,所有在线的用户将收到消息
        /// </summary>
        /// <param name="senderClientId">发送者的客户端id</param>
        /// <param name="channel">订阅名称</param>
        /// <param name="message">消息</param>
        public void SendChanMessage(Guid senderClientId, string channel, string message)
        {
            string             channelKey      = RedisKeyFormatUtil.GetSubscribeChannelKey(_appId, channel);
            var                websocketIds    = _redis.HKeys(channelKey);
            IEnumerable <Guid> receiveClientId = websocketIds.Where(a => !string.IsNullOrEmpty(a))
                                                 .Select(a => Guid.TryParse(a, out var tryuuid) ? tryuuid : Guid.Empty).ToArray();

            this.SendMessage(Guid.Empty, receiveClientId, message);
        }
        /// <summary>
        /// 加入订阅
        /// </summary>
        /// <param name="clientId">客户端id</param>
        /// <param name="channel">订阅名称</param>
        public void SubscribeChannel(Guid clientId, string channel)
        {
            string channelKey       = RedisKeyFormatUtil.GetSubscribeChannelKey(_appId, channel);
            string ClientChannelKey = RedisKeyFormatUtil.GetClientChannelKey(_appId, clientId);

            _redis.StartPipe(a => a
                             .HSet(channelKey, clientId.ToString(), 0)
                             .HSet(ClientChannelKey, channel, 0)
                             .HIncrBy(this.ChannelListKey, channel, 1));
        }
示例#4
0
        public WebSocketServerBroker(WebSocketServerConfig options) : base(options)
        {
            ClusterServer = new ConcurrentDictionary <Guid, ConcurrentDictionary <Guid, WebSocketSession> >();
            ChannelClient = new WebSocketChannelClient(options);
            _server       = options.ServerPath;
            var ServerKey       = RedisKeyFormatUtil.GetServerKey(_appId, _server);
            var OnLineServerKey = RedisKeyFormatUtil.GetOnLineServerKey(_appId);

            _redis.HSet(OnLineServerKey, _appId, _server);
            _redis.Subscribe((ServerKey, RedisSubScribleMessage));
        }
示例#5
0
        /// <summary>
        /// 连接前的负载、授权,返回 ws 目标地址,
        /// 使用该地址连接 websocket 服务端
        /// </summary>
        /// <param name="SessionId">客户端id</param>
        /// <param name="clientExtraProps">客户端相关信息,比如ip</param>
        /// <returns>websocket 地址:ws://xxxx/ws?token=xxx</returns>
        public string PrevConnectServer(Guid SessionId, string clientExtraProps)
        {
            var        server     = SelectServer(SessionId);
            var        token      = TokenUtil.GeneratorToken();
            TokenValue tokenValue = new TokenValue()
            {
                SessionId        = SessionId,
                clientExtraProps = clientExtraProps
            };
            var tokenRedisKey = RedisKeyFormatUtil.GetConnectToken(this._appId, token);

            _redis.Set(tokenRedisKey, JsonConvert.SerializeObject(tokenValue), ConstData.TokenExpireTime);
            return($"ws://{server}{_pathMatch}?token={token}");
        }
示例#6
0
        /// <summary>
        /// 新链接到达校验
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        protected TokenValue NewSessionTokenVerify(HttpContext context)
        {
            string token = context.Request.Query["token"];

            if (string.IsNullOrEmpty(token))
            {
                throw new WebSocketException((int)WebSocketErrorCodeType.TokenExpired, WebSocketErrorCodeType.TokenExpired.ToString());
            }
            var tokenRedisKey = RedisKeyFormatUtil.GetConnectToken(this._appId, token);
            var token_value   = _redis.Get(tokenRedisKey);

            if (string.IsNullOrEmpty(token_value))
            {
                throw new WebSocketException((int)WebSocketErrorCodeType.TokenExpired, WebSocketErrorCodeType.TokenExpired.ToString());
            }
            return(JsonConvert.DeserializeObject <TokenValue>(token_value));
        }
示例#7
0
        /// <summary>
        /// 负载分区规则:取SessionId后四位字符,
        /// 转成10进制数字0-65535,求模
        /// </summary>
        /// <param name="SessionId">客户端id</param>
        /// <returns></returns>
        protected string SelectServer(Guid SessionId)
        {
            string OnLineServerKey = RedisKeyFormatUtil.GetOnLineServerKey(_appId);
            var    ret             = _redis.HGetAll <string>(OnLineServerKey);

            if (ret == null || ret.Count == 0)
            {
                throw new WebSocketException((int)WebSocketErrorCodeType.ServiceNotStart, WebSocketErrorCodeType.ServiceNotStart.ToString());
            }
            _servers = ret.Values.ToList();
            var servers_idx = int.Parse(SessionId.ToString("N").Substring(28), NumberStyles.HexNumber) % _servers.Count;

            if (servers_idx >= _servers.Count)
            {
                servers_idx = 0;
            }
            return(_servers[servers_idx]);
        }
 /// <summary>
 /// 取消订阅
 /// </summary>
 /// <param name="clientId">客户端id</param>
 /// <param name="channels">订阅名称</param>
 public void UnSubscribeChannel(Guid clientId, params string[] channels)
 {
     if (channels?.Any() != true)
     {
         return;
     }
     using (var pipe = _redis.StartPipe())
     {
         string ClientChannelKey = RedisKeyFormatUtil.GetClientChannelKey(_appId, clientId);
         foreach (var channel in channels)
         {
             string channelKey = RedisKeyFormatUtil.GetSubscribeChannelKey(_appId, channel);
             pipe.HDel(channelKey, clientId.ToString())
             .HDel(ClientChannelKey, channel)
             .Eval($"if redis.call('HINCRBY', KEYS[1], '{channel}', '-1') <= 0 then redis.call('HDEL', KEYS[1], '{channel}') end return 1",
                   this.ChannelListKey);
         }
     }
 }
示例#9
0
        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="notifications"></param>
        public void SendMessage(WebSocketNotifications notifications)
        {
            Dictionary <string, NotificationsEventArgs> redata = new Dictionary <string, NotificationsEventArgs>();

            foreach (var uid in notifications.ReceiveSessionIds)
            {
                string server = SelectServer(uid);
                if (redata.ContainsKey(server) == false)
                {
                    redata.Add(server, new NotificationsEventArgs(server, notifications));
                }
                redata[server].AddReceiveClientId(uid);
            }
            foreach (var sendArgs in redata.Values)
            {
                OnSend?.Invoke(this, sendArgs);
                var ServerKey = RedisKeyFormatUtil.GetServerKey(_appId, sendArgs.Server);
                _redis.Publish(ServerKey, JsonConvert.SerializeObject(notifications));
            }
        }
        /// <summary>
        /// 获取用户参与的所有订阅
        /// </summary>
        /// <param name="clientId">客户端id</param>
        /// <returns></returns>
        public string[] GetChanListByClientId(Guid clientId)
        {
            string ClientChannelKey = RedisKeyFormatUtil.GetClientChannelKey(_appId, clientId);

            return(_redis.HKeys(ClientChannelKey));
        }
        /// <summary>
        /// 获取订阅的客户端列表
        /// </summary>
        /// <param name="channel">订阅名称</param>
        /// <returns></returns>
        public Guid[] GetChannelClientList(string channel)
        {
            string channelKey = RedisKeyFormatUtil.GetSubscribeChannelKey(_appId, channel);

            return(_redis.HKeys(channelKey).Select(a => Guid.Parse(a)).ToArray());
        }