Вывод отдельных данных из структуры на основе таймера - PullRequest
1 голос
/ 22 марта 2011

Я создаю приложение в стиле «человек посередине», которое применяет сетевую задержку к передачам, а не для злонамеренного использования, которое я должен объявить.

Однако у меня возникают проблемы с правильными механизмами вывода в структуре данных (LinkedList<string> buffer = new LinkedList<string>();).

Что должно произойти:

  • Считать данные в структуру из clientA.

    if (buffer.First != null && buffer.Last != null) { buffer.AddAfter(buffer.Last, ServerRead.ReadLine().ToString());<br> } else buffer.AddFirst(ServerRead.ReadLine().ToString());

  • Использование индивидуального или общего таймера для отслеживания того, когда следует отправлять данные в ClientB. (регулируемый таймер для настройки задержки)

  • Срабатывает таймер на элементе в структуре, освобождая пакет для клиентаB.
  • Очистить узел свободной структуры данных

    if (buffer.First != null) {<br> clientWrite.WriteLine(buffer.First.Value.ToString());<br> clientWrite.Flush();<br> buffer.RemoveFirst(); }

Однако я пытался использовать System.Windows.Forms.Timer для создания глобального таймера, который запускает поток, который обрабатывает вывод данных на clientB. Однако я считаю эту технику слишком медленной, даже при установке myTimer.Interval = 1;. Это создает проблему параллелизма, когда при очистке списка и добавлении к нему временным решением является блокировка ресурса, но я чувствую, что это добавляет к низкая производительность вывода данных.

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

С уважением, Хаус.

1 Ответ

3 голосов
/ 22 марта 2011

Связанный список будет работать, и вряд ли его блокировка (если все сделано правильно) приведет к снижению производительности. Возможно, вам было бы гораздо лучше использовать ConcurrentQueue . Это потокобезопасно, так что вам не нужно делать никаких явных блокировок.

Я бы предложил использовать System.Threading.Timer вместо таймера Windows Forms. Обратите внимание, что вы все равно будете ограничены разрешением около 15 мс. То есть даже с интервалом таймера 1 ваши эффективные времена задержки будут в диапазоне от 15 до 25 мс, а не 1 мс. Это просто способ реализации таймеров.

Кроме того, поскольку вы хотите отложить каждый элемент на определенный период времени (который я предполагаю постоянным), вам необходимо некоторое представление о «текущем времени». Я не рекомендую использовать DateTime.Now или любой из его вариантов, потому что время может измениться. Вместо этого я использую Stopwatch, чтобы получить время для конкретного приложения.

Кроме того, вам понадобится способ отслеживать время выпуска элементов. Класс для хранения элемента и время его отправки. Что-то вроде:

class BufferItem
{
    public string Data { get; private set; }
    public TimeSpan ReleaseTime { get; private set; }
    public BufferItem(string d, TimeSpan ts)
    {
        data = d;
        ReleaseTime = ts;
    }
}

Хорошо. Давайте сложим все вместе.

// the application clock
Stopwatch AppTime = Stopwatch.StartNew();
// Amount of time to delay an item
TimeSpan DelayTime = TimeSpan.FromSeconds(1.0);
ConcurrentQueue<BufferItem> ItemQueue = new ConcurrentQueue<BufferItem>();
// Timer will check items for release every 15 ms.
System.ThreadingTimer ReleaseTimer = new System.Threading.Timer(CheckRelease, null, 15, 15);

Получение предмета:

// When an item is received:
// Compute release time and add item to buffer.
var item = new BufferItem(data, AppTime.Elapsed + DelayTime);
ItemQueue.Add(item);

Таймер проц.

void CheckRelease(object state)
{
    BufferItem item;
    while (ItemQueue.TryPeek(out item) && item.ReleaseTime >= AppTime)
    {
        if (ItemQueue.TryDequeue(out item))
        {
            // send the item
        }
    }
}

Это должно работать хорошо, и у вас не должно быть проблем с параллелизмом.

Если вам не нравится этот таймер на 15 мс, который тикает все время, даже когда нет никаких элементов, вы можете сделать таймер одним выстрелом и использовать метод CheckRelease для его повторной инициализации в следующем выпуске. время после снятия предметов. Конечно, вы также должны будете заставить код приема инициализировать его в первый раз, или когда в очереди нет элементов. Вам потребуется блокировка для синхронизации доступа к обновлению таймера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...