问题描述
【背景介绍】:本人原来开发了一套多通道数据采集分析系统,分析软件开发环境是VS2010,.Net4.0,使用C#语言编写,配合NImeasurementstudio2010做图形显示,另外还用了DXPerience10的控件。多通道采集器通过UDP协议与软件进行数据通讯,软件和采集器有一套完善的通讯协议,通讯过程是这样的,软件发送数据请求包,采集器将所有24通道数据发送给软件(24包)。为保证数据完整性,软件存储策略是收到全部数据后才同意存储,否则丢弃数据,等到下一帧数据。该软件也开发完成较长时间,软件在【正常笔记本】上运行正常,win732位64位xp下都没问题。【遇到的问题】本次想继续升级采集器,在采集器内部集成了一个【工控机模块】,安装了64位Win7,和正常电脑用起来没什么区别,用的是AtomCPU,软件直接在里面运行,可以脱离笔记本采集存储数据。但是在原有软件和通讯协议未改动的情况下,发现软件在新采集器运行是实时数据显示卡顿,经常三四秒才更新数据(正常通讯是每秒请求一次数据,相应界实时数据显示也是每秒更新),起初怀疑工控机的CPU图形处理能力较差,导致界面不更新,但通过更深入的排查,发现是多线程丢包了。具体判据如下:(1)用抓包软件查看网络收发情况,发现通讯流畅不存在网络丢包的情况。(2)在软件中添加相应代码监测实时数据情况发现,问题是由于负责接收数据的线程丢失数据,导致未收到完整24通道数据,软件存储策略将这一帧的数据丢弃所致。丢失数据的情况比较随机,正常共24包数据,每次丢数据时收到数据从十几包到23包不等。(3)将线程中等待数据的时间延长,依然无法等到数据,确实是没了,不是迟了。。。【目前所做的努力】除上面所说监测代码运行情况抓包等工作外,本想将开发环境包括.net环境升级到更高版本,无奈配合使用NImesurementStudio新版本的资源比较难找,暂时还没升级。另外,原软件是在32位环境下开发的,编译成64位后也没啥改观。【相关代码】(1)主线程中等待数据代码while(true){try{allData=newbyte[ChannelCount][];receivedCount=0;//请求数据Send(reqBuffer);CanReceive=true;//开始接收intwaitTime=0;boolbOutTime=false;Thread.Sleep(6);while(receivedCount<ChannelCount)收到数据不够24通道就不处理{Thread.Sleep(40);waitTime++;Debug.WriteLine("等待中"+DateTime.Now.ToString()+"-"+DateTime.Now.Millisecond.ToString()+"waittime"+waitTime);if(waitTime>10){bOutTime=true;break;}}(2)子线程中处理数据部分代码,子线程是在主线程中开启的publicstaticvoidReceiveThreadRun(){byte[]receivebytes;while(true){try{if(!CanReceive)Thread.Sleep(2);receivebytes=Receive();while(receivedCount>=allData.Length&&CanReceive)Thread.Sleep(2);try{allData[receivedCount]=receivebytes;}catch(Exceptionex){}boolrs=处理协议数据(receivebytes);if(rs)receivedCount++;(3)子线程(2)中接收数据代码如下privatestaticbyte[]Receive(){byte[]re;MainForm.MaiInstance.网络状态=Status.Running;re=udpClient.Receive(reflocalEndPoint);//接收数据代码MainForm.MaiInstance.网络状态=Status.DarkRunning;returnre;}对代码运行情况的监测最深就带这里,丢数据时监测这里运行情况就收不到数据了目前就是以上的情况,望各位大神不吝赐教,先谢过了
解决方案
解决方案二:
看到udpClient,问题就解释的通了你用udp传输,包全丢光也是正常现象,哪里算怪问题要么换tcp,要么自己做重发机制
解决方案三:
引用1楼shingoscar的回复:
看到udpClient,问题就解释的通了你用udp传输,包全丢光也是正常现象,哪里算怪问题要么换tcp,要么自己做重发机制
的确是
解决方案四:
UDP是无状态协议,只管发送,并不管对方是否收到所以丢失数据是常态,不丢失是运气
解决方案五:
个人觉得首先应该把数据接收和数据解析分离,数据接收线程接收数据后把数据放入缓存(或线程安全的容器),然后快速返回,数据拼包和解析放到另外的线程中去。否则不是你接收不到,而是处理速度跟不上,表现为数据接收不全。
解决方案六:
sorry,还以为是tcp,原来是udp,撤回4楼的回复
解决方案七:
感谢大家回复,当初考虑到采集器芯片的处理能力,udp效率高点,另外是的单独的局域网,网络环境较好,所以选的udp之前都很好,就是换这个集成的计算机就不行了我抓包软件看到数据包已经到达网卡了,但是程序udp接收那里没了,这能完全说是用UDP协议的问题吗?
解决方案八:
引用6楼allen421的回复:
感谢大家回复,当初考虑到采集器芯片的处理能力,udp效率高点,另外是的单独的局域网,网络环境较好,所以选的udp之前都很好,就是换这个集成的计算机就不行了我抓包软件看到数据包已经到达网卡了,但是程序udp接收那里没了,这能完全说是用UDP协议的问题吗?
那是处理不过来了,数据就会丢掉,可以通过增加ReceiveBufferSize来优化不过不管你怎么弄,udp丢包是必然的
解决方案九:
4楼说得对,应该开一个死循环线程收udp包,记录接收包数,测试一下会不会丢包。理论上会丢,但在工程实践中,300mbps没问题。不要人云亦云,测试结果说话。
解决方案十:
都是扯淡,谁说UDP就要丢包,开始接收必须要异步,并且循环,代码里面那么多Sleep,怎么可能正好是非Sleep状态收到数据包,Tcp还是黑receivebytes=Receive();必须改异步,然后在endinvoke里面写结果处理
解决方案十一:
楼上那么多人,竟然讨论那么激烈,一群蠢蛋,当前线程一会Sleep一会正常工作,对方咋知道你这时候是在Sleep还是工作?必须加异步轮询,还UDP丢包不奇怪。。。。。太无知了
解决方案十二:
为什么不用异步,while(true)用信号量控制。
解决方案十三:
楼上的那些水货不用看了,直接贴上去抄吧,监听必须时刻等待对方发送内容,接收线程不能有任何Sleep,处理里面可以有,监听线程你认为正确的Sleep可能这个时候对方发了内容,可能就几十毫秒,即使你Sleep了几毫秒,也会丢数据http://cn.bing.com/search?q=udp+%E5%BC%82%E6%AD%A5+c%23&go=%E6%8F%90%E4%BA%A4&qs=n&form=QBRE&pq=udp+%E5%BC%82%E6%AD%A5+c%23&sc=0-7&sp=-1&sk=&cvid=A84DCB1E360B473A9ECF6523B64E80B2