接收数据的去重处理

botao2690 2017-12-19 11:15:06
从计算机的端口2002中不断接收BYTE数据。
接收到一个数据包后,启动一个线程进行数据处理。这个线程处理完后,会存在一段时间。所以会有多个线程并行存在。

接收到的数据包存在重复,如何去除重复的数据(需要高效)。

想法:建立一个Stream,设定大小为2M,接收到数据超过2M后,将最先进入的数据踢除(类似队列)。

多个线程访问此Stream,寻找是否有和当前处理的数据包重复的数据存在。如果有,则不进行处理。

没有这方面经验,请多指教。
...全文
655 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
SoulRed 2017-12-29
  • 打赏
  • 举报
回复
引用 14 楼 hemowolf 的回复:
[quote=引用 6 楼 DOwnstairs 的回复:] 接收到的数据包存在重复 。这句话证明你发送端存在逻辑错误,重复发送了。 建议把收到的数据交给一个特定的类去处理,接受数据只负责接受数据, 处理数据只负责处理,这样就比较简单了
嗯,我认为这是个办法 为什么发送端会发送重复的数据?从这个角度来进行逻辑判断会更好一点! 比如我的一个项目里,因为网络通信失败的原因,发送端的数据包在发送成功后,没有收到确认信息,造成发送端认为发送失败从而重发已经发过的数据。我们的做法是,每个数据包会有一个流水号,流水号值是整数递增的,这样发送端标识 + 流水号 就可以唯一地标识一个数据包了。[/quote] 我也做网络相关的组件,你这样的问题一般是网络异步多线程没有做好锁。 网络的锁非常难搞好。需要一点一点的调试。。祝你好运
小灰狼 2017-12-21
  • 打赏
  • 举报
回复
引用 6 楼 DOwnstairs 的回复:
接收到的数据包存在重复 。这句话证明你发送端存在逻辑错误,重复发送了。 建议把收到的数据交给一个特定的类去处理,接受数据只负责接受数据, 处理数据只负责处理,这样就比较简单了
嗯,我认为这是个办法 为什么发送端会发送重复的数据?从这个角度来进行逻辑判断会更好一点! 比如我的一个项目里,因为网络通信失败的原因,发送端的数据包在发送成功后,没有收到确认信息,造成发送端认为发送失败从而重发已经发过的数据。我们的做法是,每个数据包会有一个流水号,流水号值是整数递增的,这样发送端标识 + 流水号 就可以唯一地标识一个数据包了。
botao2690 2017-12-19
  • 打赏
  • 举报
回复
这里边我忘了一点,每个数据包有自己的包头包尾,并且内置了校验字符,所以不会产生12345 和123的情况。没有时戳,我曾经也这样处理过,定义一个待时间戳的类,用LIST,但处理效率不好
wanghui0380 2017-12-19
  • 打赏
  • 举报
回复
其实把微软都帮你做了。 比如TPL dataflow里面的TransformBlock。 ps:其实没有什么去重操作,他只是一个input,一个output
xuzuning 2017-12-19
  • 打赏
  • 举报
回复
收到 12345 之后,又收到 123 你能说那个 123 是重复的吗?显然不能,至少他的时序是不同的 每个线程处理后的数据都应统一汇集到一个公共载体中,以便后续程序加一利用 如果后续的业务认为那是重复的,那也是后续逻辑的事情,与接收无关 由于线程并不是立即运行的,所以 处理 123 的线程,可能先于处理 12345 的线程结束 那么是 123 的123 与 12345 的123 重复了,还是 12345 的123 与 123 的 123 重复了,你又是如何甄别的呢
xian_wwq 2017-12-19
  • 打赏
  • 举报
回复
不知道业务数据是否携带时戳信息, 如果有时戳,可以创建个Hash,以数据标识为主键,Hash中保存最新时间, 每进来一笔数据,去Hash中查询主键,比对时戳 如果早于或等于,则抛弃;否则更新。 为了提供比对效率,时戳转换为int来保存。 因为多线程操作,这个Hash需要加读写锁。
  • 打赏
  • 举报
回复
在 windows 系统下CPU、外设等等都有很大的延迟,处理过程非常复杂,并不是都像上面我举的例子那样是个简单的计算之类的过程。比如说500个并发过程即使在系统线程池故意缓慢地分配线程的情况下,并发(分时)处理也比顺序排队处理,整体的处理时间变得更快。单个任务的平均处理时间可能稍慢一点(比如说从80毫秒变为110毫秒),但是(中间有着数据库、显示等等各种外设交互式访问操作的)整体的处理速度变快了,比如说从100秒钟缩短为5秒钟。所谓的队列——排几个长队——除了看上去整齐一点,能有什么技术含量呢?并发计算、异步处理,以及事件驱动式的系统设计,才是你最需要熟悉的 .net 技术知识。
  • 打赏
  • 举报
回复
理解线程池机制,从而能够用系统线程池自动管理每一个独立的数据处理任务,这其实编程知识的优势。而所谓的“队列”,我认为至少不算是 .net 技术的主流概念,只能算是10年前的 java 一些书或者20年前的 unix/c++ 的旧书上的一些结构理论而已。
圣殿骑士18 2017-12-19
  • 打赏
  • 举报
回复
每个数据包用一个线程去处理,我觉得你设计过度了。原则上,总体用一个线程来接收处理就够了。
  • 打赏
  • 举报
回复
你可以试试把最后一个方法写为
        static void proc(int data)
        {
            Console.WriteLine("判断数据 {0}", data);
            lock (lst)
            {
                if (lst.Contains(data))
                    return;

                lst.Add(data);
                if (lst.Count >= 6)
                    lst.RemoveRange(0, 3);

                Thread.Sleep(new Random().Next(0, 1000));    //模拟耗时操作
                Console.WriteLine("\t\t\t返回为 {0}", data);
            }
        }
这时候就会发现整个处理过程多用了很多时间才完成。 实际上纠结具体的某个语句、某个数据结构,并不会在这里真正提高多少效率。问题主要出在滥用同步加锁范围、或者就是滥用“队列概念”上了。如果你在线程中尽可能少地代码、短的代码才放在同步 lock{.....} 中间,而不是长时间同步,则能保证更高的并发执行效率。否则纠结再高达上的数据结构名词儿,也不会提高什么效率。
  • 打赏
  • 举报
回复
引用 4 楼 botao2690 的回复:
这里边我忘了一点,每个数据包有自己的包头包尾,并且内置了校验字符,所以不会产生12345 和123的情况。没有时戳,我曾经也这样处理过,定义一个待时间戳的类,用LIST,但处理效率不好
你可以用"两个List<T>"轮流保存数据,一个使用完毕则立即重新实例化(释放),这样就能保证最小n个单元缓存、最大n+n个单元缓存。问题是这样的数据结构,跟写一句
                if (lst.Count >= 6)
                    lst.RemoveRange(0, 3);
其实差别也并不大。
  • 打赏
  • 举报
回复
我给你写一个控制台的例子:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            ThreadPool.QueueUserWorkItem(h => proc(1));
            ThreadPool.QueueUserWorkItem(h => proc(2));
            ThreadPool.QueueUserWorkItem(h => proc(3));
            ThreadPool.QueueUserWorkItem(h => proc(4));
            ThreadPool.QueueUserWorkItem(h => proc(2));
            ThreadPool.QueueUserWorkItem(h => proc(5));
            ThreadPool.QueueUserWorkItem(h => proc(3));
            ThreadPool.QueueUserWorkItem(h => proc(1));
            ThreadPool.QueueUserWorkItem(h => proc(2));
            ThreadPool.QueueUserWorkItem(h => proc(5));
            ThreadPool.QueueUserWorkItem(h => proc(3));
            ThreadPool.QueueUserWorkItem(h => proc(6));
            ThreadPool.QueueUserWorkItem(h => proc(3));
            ThreadPool.QueueUserWorkItem(h => proc(4));
            ThreadPool.QueueUserWorkItem(h => proc(2));
            ThreadPool.QueueUserWorkItem(h => proc(5));
            ThreadPool.QueueUserWorkItem(h => proc(6));
            ThreadPool.QueueUserWorkItem(h => proc(3));
            ThreadPool.QueueUserWorkItem(h => proc(4));
            Console.WriteLine("....................按任意键结束");
            Console.ReadKey();
        }

        private static List<int> lst = new List<int>();

        static void proc(int data)
        {
            Console.WriteLine("判断数据 {0}", data);
            lock (lst)
            {
                if (lst.Contains(data))
                    return;

                lst.Add(data);
                if (lst.Count >= 6)
                    lst.RemoveRange(0, 3);
            }
            Thread.Sleep(new Random().Next(0, 1000));    //模拟耗时操作
            Console.WriteLine("\t\t\t返回为 {0}", data);
        }
    }
}

这里,以并发多线程方式调用 proc(data) 来处理多个数据,使用 lst 来保存缓冲重复数据,并且当它长度为6 时截断前边3个单元(先入先出)。 你可以看到,这里使用 lock 来同步线程处理中的查重部分(因为这部分如果并发执行则会有冲突),而一旦查重结束则后边的耗时操作就并发执行了(从打印结果的”乱“其实就能看出这里恰好达到了并发处理耗时操作的目的)。
wanghui0380 2017-12-19
  • 打赏
  • 举报
回复
一图胜万语,lz看一下下面的图就知道了


这里其实没有什么去重操作,只是两个队列,一个task
SoulRed 2017-12-19
  • 打赏
  • 举报
回复
接收到的数据包存在重复 。这句话证明你发送端存在逻辑错误,重复发送了。 建议把收到的数据交给一个特定的类去处理,接受数据只负责接受数据, 处理数据只负责处理,这样就比较简单了
xian_wwq 2017-12-19
  • 打赏
  • 举报
回复
引用 4 楼 botao2690 的回复:
这里边我忘了一点,每个数据包有自己的包头包尾,并且内置了校验字符,所以不会产生12345 和123的情况。没有时戳,我曾经也这样处理过,定义一个待时间戳的类,用LIST,但处理效率不好
具体处理效率要要达到多少呢? 秒级?毫秒级? 既然有校验,可以考虑类似于文件md5的方法来判定重复

110,537

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧