Никакая другая функция не работает с таймером, запущенным в консольном приложении - PullRequest
0 голосов
/ 20 ноября 2018

Я использую системный таймер таймера в консольном приложении прослушивателя асинхронного сокета.Я хочу, чтобы таймер запускался каждые 40 секунд и проверял состояние подключения клиентских устройств.

Как только таймер запускается, сокет сервера больше не прослушивает (не ожидает больше подключений), и только данные могут быть получены все время1-м устройством, которое было подключено.Когда я вынул устройство из сети и снова подключился, ничего не происходило.Никакая другая функция не работает.Вот код для таймера -

IPStatusTimer = new System.Timers.Timer(35000);
        IPStatusTimer.Elapsed += IPStatusTimer_Elapsed;
        IPStatusTimer.AutoReset = true;
        IPStatusTimer.Enabled = true;

  private static void IPStatusTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        Console.WriteLine("Inside Timer");
        if (connectedClient > 0)
        {
            foreach (KeyValuePair<string, int> i in IPStatus)
            {
                if (i.Value == 1)
                {
                    IPStatus[i.Key] = 0;
                }
                else if (i.Value == 0)
                {
                    Decode dr = new Decode();
                    string m = dr.offlineMessage();
                    if (Clients.Count > 0)
                    {
                        foreach (KeyValuePair<int, StateObject> c in Clients)
                        {
                            if (((IPEndPoint)c.Value.workSocket.RemoteEndPoint).Address.ToString() == i.Key)
                            {
                                Clients.Remove(c.Key);
                            }
                        }
                        SendMessage(i.Key, m);
                    }
                }
            }
        }
    }

Таймер не должен влиять на другие мои функции.Это должно спокойно работать в фоновом режиме, пока приложение не работает.

РЕДАКТИРОВАТЬ: (в приведенном выше коде) Добавлен, если CLients.Count> 0, то только удалит элемент из CLients, так что там не будет никаких исключений.

Всякий раз, когда есть соединение, которое я добавляюStateобъект для словаря, так что я могу транслировать данные всем клиентам, когда требуется.

    public static void AcceptCallback(IAsyncResult ar)
    {
        connectedClient++;
        // Signal the main thread to continue.  
        allDone.Set();
        // Get the socket that handles the client request.  
        Socket listener = (Socket)ar.AsyncState;
        Socket handler = listener.EndAccept(ar);
        string ip = ((IPEndPoint)handler.RemoteEndPoint).Address.ToString();
        Console.WriteLine("ip   " + ip);
        // Create the state object.  
        StateObject state = new StateObject();
        state.buffer = new byte[StateObject.BufferSize];
        Clients.Add(connectedClient, state);
        if (IPStatus.ContainsKey(ip))
            IPStatus[ip] = 1;
        else
        IPStatus.Add(ip, 1);
        Console.WriteLine(" Total Connected client : " + connectedClient);
        state.workSocket = handler;           
        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
            new AsyncCallback(ReadCallback), state);
    }       

Так, как вы можете видеть. Если клиент вернулся в сеть, а сервер всегда находится в режиме прослушивания, он должен принятьобъект соединения и состояния должен быть снова добавлен в клиент (объект словаря).Это не должно быть проблемой.И как только клиент подключается, я присваиваю IPStatus (объекту словаря) значение 1, поскольку это означает, что клиент находится в сети.

Затем в моем readCallBack () всякий раз, когда я получаю данные от любого клиента, затем в моем словаре, Я снова устанавливаю его значение на 1 в IPStatus.

 public static void ReadCallback(IAsyncResult ar)
    {
        string content = string.Empty;

        // Retrieve the state object and the handler socket  
        // from the asynchronous state object.  
        StateObject state = (StateObject)ar.AsyncState;
        Socket handler = state.workSocket;
        // Read data from the client socket.   
        int bytesRead = handler.EndReceive(ar);
        int i = 0;
        string ip = ((IPEndPoint)handler.RemoteEndPoint).Address.ToString();
        if (IPStatus.ContainsKey(ip))
        {
            IPStatus[ip] = 1;
            }
}

И когда таймер запускается, если значение любого IP равно 1, я устанавливаю его на 0. Так что в следующий раз, если таймер работает, и он получаетзначение 0 означает, что он не получил никаких данных от клиента за последние 35 секунд, что означает, что клиент больше не подключен к сети.ReadCallback и все происходит с использованием StateObject, а не с клиентами (dictinary Object).Поэтому, если я удаляю какой-либо элемент из клиентов, я добавляю его снова, когда начинается любое новое соединение.

Надеюсь, мой сценарий станет более понятным для вас, ребята.

1 Ответ

0 голосов
/ 21 ноября 2018

Благодаря @ rs232 ... чтобы указать причину исключения.Это был объект словаря, который выдавал ошибку.Так что использовали блокировку (объект) перед операцией чтения и записи по словарю.

lock (Clients)
                    {
                        if (Clients.Count > 0)
                        {
                            foreach (KeyValuePair<string, StateObject> c in Clients)
                            {
                                if (c.Value.workSocket == handler)
                                {
                                    Clients.Remove(c.Key);
                                    Console.WriteLine("Client automatically disconnected");
                                    Decode dr = new Decode();
                                    string m = dr.offlineMessage();
                                    SendMessage(ip, m);
                                    break;
                                }
                            }
                        }
                    }

И для всех, кто заходит на эту страницу, думает о проблеме таймера.Код выше (в вопросе) прекрасно, работает как требуется.Вы можете взять ссылку из этого.

...