예제 #1
0
        private void DoTask()
        {
            if (taskQueue.Count > 0)
            {
                bool res = taskQueue.TryDequeue(out OperateObject result);
                if (res)
                {
                    try
                    {
                        if (result.ope != MsgOperation.登录校验)
                        {
                            if (!loginDic.ContainsKey(result.workSocket) || !loginDic[result.workSocket])
                            {
                                Console.WriteLine($" ip=[{result.workSocket.RemoteEndPoint.ToString()}] 尚未登录! 无法执行后续操作");
                                return;
                            }
                        }

                        switch (result.ope)
                        {
                        //这个用服务端主动[推] ,服务端不保存发布消息
                        case MsgOperation.发布广播:
                        {
                            PublishObject publishObject = (PublishObject)result.body;
                            Task.Run(() =>
                                {
                                    //订阅者中有人关注这个话题 就向订阅者发送消息
                                    if (subscribeListSocket.ContainsKey(publishObject.topic))
                                    {
                                        Console.WriteLine($"准备发布消息给Socket订阅者,订阅数:{subscribeListSocket[publishObject.topic].Count}");
                                        //并行执行,任务开销大的时候效率高于单纯的for循环
                                        Parallel.ForEach(subscribeListSocket[publishObject.topic], (socket) =>
                                        {
                                            if (socket != null && socket.Connected)
                                            {
                                                Send(socket, publishObject.content, MsgOperation.发布广播);
                                            }
                                        });
                                    }

                                    if (subscribeListHttp.ContainsKey(publishObject.topic))
                                    {
                                        Console.WriteLine($"准备发布消息给Http订阅者,订阅数:{subscribeListHttp[publishObject.topic].Count}");
                                        //并行执行,任务开销大的时候效率高于单纯的for循环
                                        Parallel.ForEach(subscribeListHttp[publishObject.topic], (notifyUrl) =>
                                        {
                                            string resp = HttpHelper.PostJsonData(notifyUrl, JsonConvert.SerializeObject(publishObject.content)).Result;
                                        });
                                    }
                                });
                        }
                        break;

                        //采用得是服务端主动[推]的轮询模式,一个个按顺序发   不推荐使用  客户端主动拉比较好
                        case MsgOperation.发布消息:
                        {
                            PublishObject publishObject = (PublishObject)result.body;
                            Task.Run(() =>
                                {
                                    //订阅者中有人关注这个话题 就向订阅者发送消息
                                    if (subscribeListSocket.ContainsKey(publishObject.topic) && subscribeListSocket[publishObject.topic].Count > 0)
                                    {
                                        //轮询发
                                        Console.WriteLine($"准备发布消息给Socket订阅者,订阅数:{subscribeListSocket[publishObject.topic].Count}");
                                        tryTakeSocketAgain:
                                        subscribeListSocket[publishObject.topic].TryDequeue(out Socket socket);    //头部取出来
                                        if (socket == null || !socket.Connected)
                                        {
                                            QueueHelper.Remove(ref subscribeListSocket, publishObject.topic, socket);
                                            goto tryTakeSocketAgain;
                                        }
                                        Send(socket, publishObject.content, MsgOperation.发布消息);
                                        if (!subscribeListSocket[publishObject.topic].Contains(socket))
                                        {
                                            subscribeListSocket[publishObject.topic].Enqueue(socket);    //加入到尾部去
                                        }
                                    }

                                    if (subscribeListHttp.ContainsKey(publishObject.topic) && subscribeListHttp[publishObject.topic].Count > 0)
                                    {
                                        Console.WriteLine($"准备发布消息给Http订阅者,订阅数:{subscribeListHttp[publishObject.topic].Count}");
                                        tryTakeHttpAgain:
                                        subscribeListHttp[publishObject.topic].TryDequeue(out string notifyUrl);    //头部取出来
                                        string resp = HttpHelper.PostJsonData(notifyUrl, JsonConvert.SerializeObject(publishObject.content)).Result;
                                        if (resp == null || resp.ToUpper() != "SUCCESS")
                                        {
                                            QueueHelper.Remove(ref subscribeListHttp, publishObject.topic, notifyUrl);
                                            goto tryTakeHttpAgain;
                                        }
                                        if (!subscribeListHttp[publishObject.topic].Contains(notifyUrl))
                                        {
                                            subscribeListHttp[publishObject.topic].Enqueue(notifyUrl);    //加入到尾部去
                                        }
                                    }
                                });
                        }
                        break;

                        //采用客户端来自己[拉]取,服务端保存消息队列,可以实现一个消息只会被一个订阅者拉取消费,这样客户端可以在做一个操作,在自己任务量少于N条时,有余力处理消息就可以向服务器拉取数据,可以保持负载均衡.
                        case MsgOperation.发布消息存消息队列:
                        {
                            int           failcount     = 3;
                            PublishObject publishObject = (PublishObject)result.body;
tryStorePublishMsgSocketAgain:
                            if (publishMsgList.ContainsKey(publishObject.topic))
                            {
                                publishMsgList[publishObject.topic].Enqueue(publishObject.content);
                            }
                            else
                            {
                                ConcurrentQueue <object> _cache = new ConcurrentQueue <object>();
                                _cache.Enqueue(publishObject.content);
                                bool success = publishMsgList.TryAdd(publishObject.topic, _cache);
                                if (!success)
                                {
                                    failcount++;
                                    if (failcount > 3)
                                    {
                                        break;
                                    }
                                    goto tryStorePublishMsgSocketAgain;
                                }
                            }
                        }
                        break;

                        case MsgOperation.订阅消息Socket方式:
                        {
                            int             failcount       = 3;
                            SubscribeObject subscribeObject = (SubscribeObject)result.body;
trySubscribeSocketAgain:
                            if (subscribeListSocket.ContainsKey(subscribeObject.topic))
                            {
                                if (!subscribeListSocket[subscribeObject.topic].Contains(result.workSocket))
                                {
                                    subscribeListSocket[subscribeObject.topic].Enqueue(result.workSocket);
                                }
                            }
                            else
                            {
                                ConcurrentQueue <Socket> _cache = new ConcurrentQueue <Socket>();
                                _cache.Enqueue(result.workSocket);
                                bool success = subscribeListSocket.TryAdd(subscribeObject.topic, _cache);
                                if (!success)
                                {
                                    failcount++;
                                    if (failcount > 3)
                                    {
                                        break;
                                    }
                                    goto trySubscribeSocketAgain;
                                }
                            }
                        }
                        break;

                        case MsgOperation.订阅消息Http方式:
                        {
                            int             failcount       = 3;
                            SubscribeObject subscribeObject = (SubscribeObject)result.body;
                            if (string.IsNullOrEmpty(subscribeObject.notifyUrl))
                            {
                                break;
                            }
trySubscribeHttpAgain:
                            if (subscribeListHttp.ContainsKey(subscribeObject.topic))
                            {
                                if (!subscribeListHttp[subscribeObject.topic].Contains(subscribeObject.notifyUrl))
                                {
                                    subscribeListHttp[subscribeObject.topic].Enqueue(subscribeObject.notifyUrl);
                                }
                            }
                            else
                            {
                                ConcurrentQueue <string> _cache = new ConcurrentQueue <string>();
                                _cache.Enqueue(subscribeObject.notifyUrl);
                                bool success = subscribeListHttp.TryAdd(subscribeObject.topic, _cache);
                                if (!success)
                                {
                                    failcount++;
                                    if (failcount > 3)
                                    {
                                        break;
                                    }
                                    goto trySubscribeHttpAgain;
                                }
                            }
                        }
                        break;

                        //没有主题或者没消息暂时先不通知客户端
                        case MsgOperation.客户端主动拉取消息:
                        {
                            SubscribeObject subscribeObject = (SubscribeObject)result.body;
                            if (publishMsgList.ContainsKey(subscribeObject.topic))
                            {
tryPullMsgAgain:
                                if (publishMsgList[subscribeObject.topic].Count > 0)
                                {
                                    if (string.IsNullOrEmpty(subscribeObject.notifyUrl))
                                    {
                                        //回给socket
                                        bool isGet = publishMsgList[subscribeObject.topic].TryDequeue(out object data);
                                        if (isGet)
                                        {
                                            Send(result.workSocket, data, MsgOperation.客户端主动拉取消息);
                                        }
                                        else
                                        {
                                            goto tryPullMsgAgain;
                                        }
                                    }
                                    else
                                    {
                                        //回给notifyUrl
                                        bool isGet = publishMsgList[subscribeObject.topic].TryDequeue(out object data);
                                        if (isGet)
                                        {
                                            var resp = HttpHelper.PostJsonData(subscribeObject.notifyUrl, JsonConvert.SerializeObject(publishMsgList[subscribeObject.topic])).Result;
                                        }
                                        else
                                        {
                                            goto tryPullMsgAgain;
                                        }
                                    }
                                }
                            }
                        }
                        break;

                        case MsgOperation.取消订阅:
                        {
                            SubscribeObject subscribeObject = (SubscribeObject)result.body;
                            if (subscribeListSocket.ContainsKey(subscribeObject.topic) && subscribeListSocket[subscribeObject.topic].Contains(result.workSocket))
                            {
                                Task.Run(() =>
                                    {
                                        QueueHelper.Remove(ref subscribeListSocket, subscribeObject.topic, result.workSocket);
                                    });
                            }

                            if (subscribeListHttp.ContainsKey(subscribeObject.topic) && subscribeListHttp[subscribeObject.topic].Contains(subscribeObject.notifyUrl))
                            {
                                Task.Run(() =>
                                    {
                                        QueueHelper.Remove(ref subscribeListHttp, subscribeObject.topic, subscribeObject.notifyUrl);
                                    });
                            }
                        }
                        break;

                        case MsgOperation.登录校验:
                        {
                            AccessObject access       = (AccessObject)result.body;
                            AccessResult accessResult = new AccessResult();
                            if (access != null)
                            {
                                if (!accessDic.ContainsKey(access.AccessKeyId))
                                {
                                    accessResult.Code    = -1;
                                    accessResult.Message = $"[{result.workSocket.RemoteEndPoint.ToString()}]您没有登录权限";
                                    Send(result.workSocket, accessResult, MsgOperation.登录校验);
                                    return;
                                }

                                DateTime loginTime = Parse.TS2DT(Convert.ToDouble(access.CurrentTimeSpan));
                                if (loginTime < DateTime.Now.AddMinutes(-5) || loginTime > DateTime.Now.AddMinutes(5))
                                {
                                    accessResult.Code    = -1;
                                    accessResult.Message = $"[{result.workSocket.RemoteEndPoint.ToString()}]CurrentTimeSpan超时";
                                    Send(result.workSocket, accessResult, MsgOperation.登录校验);
                                    return;
                                }

                                string prepay = access.AccessKeyId + access.CurrentTimeSpan + accessDic[access.AccessKeyId];
                                string sign   = MD5Helper.Sign(prepay);
                                if (sign.Equals(access.Sign.ToUpper()))
                                {
                                    loginDic.TryAdd(result.workSocket, true);
                                    accessResult.Code    = 0;
                                    accessResult.Message = $"[{result.workSocket.RemoteEndPoint.ToString()}]登录成功";
                                    Send(result.workSocket, accessResult, MsgOperation.登录校验);
                                }
                                else
                                {
                                    accessResult.Code    = -1;
                                    accessResult.Message = $"[{result.workSocket.RemoteEndPoint.ToString()}]登录失败";
                                    Send(result.workSocket, accessResult, MsgOperation.登录校验);
                                }
                            }
                        }
                        break;

                        default:
                            break;
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"task任务处理失败 ip:[{result.workSocket.RemoteEndPoint.ToString()}] ex:{ex}");
                    }
                }
            }
        }
예제 #2
0
        private void ReadCallback(IAsyncResult ar)
        {
            Socket handler = null;

            try
            {
                // Retrieve the state object and the handler socket
                // from the asynchronous state object.
                StateObject state = (StateObject)ar.AsyncState;
                handler = state.workSocket;
                // Read data from the client socket.
                int bytesRead = handler.EndReceive(ar);
                if (bytesRead > 0)
                {
                    //不管是不是第一次接收,只要接收字节总长度小于4
                    if (state.readBufferLength + bytesRead < 4)
                    {
                        Array.Copy(state.buffer, 0, state.totalBuffer, state.readBufferLength, bytesRead);
                        state.readBufferLength += bytesRead;
                        //继续接收
                        state.buffer = new byte[StateObject.BufferSize];
                        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
                        return;
                    }

                    //已读长度如果小于4 要先获取总的消息长度
                    if (state.readBufferLength < 4)
                    {
                        //先拼出消息体长度
                        byte[] totalLengthBytes = new byte[4];
                        if (state.readBufferLength > 0)
                        {
                            Array.Copy(state.totalBuffer, 0, totalLengthBytes, 0, state.readBufferLength);
                        }
                        int readLength = 4 - state.readBufferLength;
                        Array.Copy(state.buffer, 0, totalLengthBytes, state.readBufferLength, readLength);
                        state.totalLength = ByteConvert.Bytes2UInt(totalLengthBytes);
                        state.totalBuffer = new byte[state.totalLength];
                    }

                    //还是没读完
                    if (state.totalLength > state.readBufferLength + bytesRead)
                    {
                        Array.Copy(state.buffer, 0, state.totalBuffer, state.readBufferLength, bytesRead);
                        state.readBufferLength += bytesRead;
                        //继续接收
                        state.buffer = new byte[StateObject.BufferSize];
                        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
                        return;
                    }

                    //已经够读完了
                    Array.Copy(state.buffer, 0, state.totalBuffer, state.readBufferLength, state.totalLength - state.readBufferLength);

                    Task.Run(() =>
                    {
                        Handle(state);
                    });



                    //继续接收这个客户端发来的下一个消息
                    StateObject nextState = new StateObject();
                    nextState.workSocket = handler;
                    if (state.readBufferLength + bytesRead > state.totalLength)
                    {
                        //这里说明一个完整的消息体接收完了,有可能还会读到下一次的消息体
                        byte[] newTotalBuffer = new byte[state.readBufferLength + bytesRead - state.totalLength];
                        Array.Copy(state.buffer, state.totalLength - state.readBufferLength, newTotalBuffer, 0, state.readBufferLength + bytesRead - state.totalLength);
                        //要重新建一个对象,不然会影响到异步执行后续处理方法
                        nextState.readBufferLength = newTotalBuffer.Length;
                        if (nextState.readBufferLength >= 4)
                        {
                            //拼出消息体长度
                            byte[] totalLengthBytes = new byte[4];
                            Array.Copy(newTotalBuffer, 0, totalLengthBytes, 0, 4);
                            nextState.totalLength = ByteConvert.Bytes2UInt(totalLengthBytes);
                            nextState.totalBuffer = new byte[nextState.totalLength];
                        }
                        Array.Copy(newTotalBuffer, 0, nextState.totalBuffer, 0, nextState.readBufferLength);
                    }
                    handler.BeginReceive(nextState.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), nextState);
                }
            }
            catch (SocketException ex)
            {
                Console.WriteLine(ex.ToString());
                if (ex.ErrorCode == 10054)//断开连接了
                {
                    if (handler == null)
                    {
                        return;
                    }

                    //登录状态移除
                    loginDic.TryRemove(handler, out bool loginResult);

                    Task.Run(() =>
                    {
                        foreach (var item in subscribeListSocket)
                        {
                            //队列移除
                            QueueHelper.Remove(ref subscribeListSocket, item.Key, handler);
                        }
                    });
                }
            }
        }