Это действительно зависит от того, как вы получаете ваши данные - хотя технически протокол не должен давать вам дубликаты (то есть пакеты с одинаковой контрольной суммой tcp), другие факторы могут привести к тому, что вы увидите дубликаты - например, сетевое оборудование, которым вы являетесь с помощью; также, если вы используете снифферы для просмотра потоков tcp, а не просто для чтения открытого сокета в своем приложении, возможно получить дублирующие пакеты от снифферов, даже если у реальных потоков tcp, которые они отслеживали, не было дублированных пакетов.
Чтобы привести пример из реальной жизни. В настоящее время я работаю над некоторым анализом tcp внутренних сетей для крупной фондовой биржи, и данные, на которые я обращаюсь, поступают от нескольких анализаторов и собираются вместе. Таким образом, извлекая данные, я обнаружил, что мне нужно выполнить ряд предварительных этапов, включая поиск и удаление дубликатов. Например, в только что прочитанном потоке из примерно 60 000 пакетов данных я обнаружил и удалил 95 дублированных пакетов.
Стратегия, которую я здесь использую, заключается в том, чтобы сохранять скользящее окно 10 последних контрольных сумм tcp и игнорировать пакеты, которые соответствуют этим контрольным суммам. Обратите внимание, что это хорошо работает для пакетов PSH, но не так хорошо для пакетов ACK - но я все равно меньше беспокоюсь об этом.
Я написал специальную коллекцию для отслеживания этого скользящего окна контрольных сумм tcp, которая может быть полезна для других:
/// <summary>
/// Combination of a double-linked-list and a hashset with a max bound;
/// Works like a bounded queue where new incoming items force old items to be dequeued;
/// Re-uses item containers to avoid GC'ing;
/// Public Add() and Contains() methods are fully thread safe through a ReaderWriterLockSlim;
/// </summary>
public class BoundedHashQueue<T>
{
private readonly int _maxSize = 100;
private readonly HashSet<T> _hashSet = new HashSet<T>();
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
private readonly Item _head;
private readonly Item _tail;
private int _currentCount = 0;
public BoundedHashQueue(int maxSize)
{
_maxSize = maxSize;
_head = _tail = new Item();
}
private class Item
{
internal T Value;
internal Item Next;
internal Item Previous;
}
public void Add(T value)
{
_lock.Write(() =>
{
if (_currentCount == 0)
{
Item item = new Item();
item.Value = value;
_head.Next = item;
item.Previous = _head;
item.Next = _tail;
_tail.Previous = item;
_currentCount++;
}
else
{
Item item;
if (_currentCount >= _maxSize)
{
item = _tail.Previous;
_tail.Previous = item.Previous;
_tail.Previous.Next = _tail;
_hashSet.Remove(item.Value);
}
else
{
item = new Item();
_currentCount++;
}
item.Value = value;
item.Next = _head.Next;
item.Next.Previous = item;
item.Previous = _head;
_head.Next = item;
_hashSet.Add(value);
}
});
}
public bool Contains(T value)
{
return _lock.Read(() => _hashSet.Contains(value));
}
}}