当前位置:编程学习 > C#/ASP.NET >>

C# 串口编程数据不完整以及处理大数据丢失数据的问题

我现在在用C#的串口 来和仪器通讯,但数据总是接收不完整(数据包的类型有很多种),该如何处理,还有就是仪器会实时的给我发数据,但通常会丢数据,网上说可以用多线程和数据池的方法解决,但看到不是很明白,有大神可以帮忙解决吗 --------------------编程问答-------------------- 自己顶一下。。。。 --------------------编程问答-------------------- 我也在问这个问题 --------------------编程问答-------------------- 你的通讯协议是什么样的,很完整吗? --------------------编程问答--------------------    //  昨天的comport.ReadExisting()问题困扰着我,如何读取到完整的PLC代码呢?今天终于解决了。我的思路还是对着的,不停地读取缓冲区的数据,直到把完整的代码读完。但是忽略了port_StringDataReceived时间的触发问题,再找到 ReceivedBytesThreshold关键词后进行了搜索,理解了port_StringDataReceived事件的控制,然后就是写不停地读取缓冲区的数据,直到把完整的代码读完的算法,这里要说的是,半路出家很多细节问题要解决,我刚开始只是注意功能的实现,没有注意捕捉程序异常,处理异常,使得程序不能完整的运行。再经历了一上午的努力终于实现了数据的监测,就是速率有点慢。这都是单线程惹的祸,看来还得学习一下后台线程的使用。

        //   下面是我的代码,这里要感谢SCDN论坛的 Yali8 网友,他的算法的完整性很高,我在他的基础上进行了修改,得到了我想要的代码。还要感谢网友 剑客  QQ:316722224 ,给我的耐心解答。下面分享一下我的成果~

        //代码生活之使用ReadExisting()读取缓冲区内PLC响应的完整代码 


        //    ReceivedBytesThreshold只是触发DataReceived事件的一个阀值,由于串口通讯的实时性,很难说你每次读取的数据长度就是阀值的长度。请参考下面的方法。 

        //一、技术要点: 
        //(1).首先,SerialPort的ReceivedBytesThreshold先设置成1,表示只要有1个字符送达端口时便触发DataReceived事件 
        //(2).当DataReceived触发时,先把ReceivedBytesThreshold设置成一个比较大的值,达到读取本次端口数据时,不再触发DataReceived. 
        //(3).循环读取端口中的数据,直至读完。 
        //(4).移除读取数据中的非法字符。 
        //(5).触发一个后台线程处理收到的数据。 
        //(6).在finally中把ReceivedBytesThreshold重置回1 
        //二、C# Code

        //调用将代码翻译为数据的子程序,返回值为带符号十进制整数
        //if (PLCCode.Length == 25)
        //{
        //    data = PLCCodeToStringData(PLCCode);
        //    string LWA = data[0];
        //    string RWA = data[1];
        //    LogMonitoringPage(LWA, RWA);         // 显示有效信息到监测界面

        //}
        //Log(LogMsgType.Incoming, PLCCode);      // 显示所有信息 --------------------编程问答--------------------
引用 4 楼 u013096183 的回复:
   //  昨天的comport.ReadExisting()问题困扰着我,如何读取到完整的PLC代码呢?今天终于解决了。我的思路还是对着的,不停地读取缓冲区的数据,直到把完整的代码读完。但是忽略了port_StringDataReceived时间的触发问题,再找到 ReceivedBytesThreshold关键词后进行了搜索,理解了port_StringDataReceived事件的控制,然后就是写不停地读取缓冲区的数据,直到把完整的代码读完的算法,这里要说的是,半路出家很多细节问题要解决,我刚开始只是注意功能的实现,没有注意捕捉程序异常,处理异常,使得程序不能完整的运行。再经历了一上午的努力终于实现了数据的监测,就是速率有点慢。这都是单线程惹的祸,看来还得学习一下后台线程的使用。

        //   下面是我的代码,这里要感谢SCDN论坛的 Yali8 网友,他的算法的完整性很高,我在他的基础上进行了修改,得到了我想要的代码。还要感谢网友 剑客  QQ:316722224 ,给我的耐心解答。下面分享一下我的成果~

        //代码生活之使用ReadExisting()读取缓冲区内PLC响应的完整代码 


        //    ReceivedBytesThreshold只是触发DataReceived事件的一个阀值,由于串口通讯的实时性,很难说你每次读取的数据长度就是阀值的长度。请参考下面的方法。 

        //一、技术要点: 
        //(1).首先,SerialPort的ReceivedBytesThreshold先设置成1,表示只要有1个字符送达端口时便触发DataReceived事件 
        //(2).当DataReceived触发时,先把ReceivedBytesThreshold设置成一个比较大的值,达到读取本次端口数据时,不再触发DataReceived. 
        //(3).循环读取端口中的数据,直至读完。 
        //(4).移除读取数据中的非法字符。 
        //(5).触发一个后台线程处理收到的数据。 
        //(6).在finally中把ReceivedBytesThreshold重置回1 
        //二、C# Code

        //调用将代码翻译为数据的子程序,返回值为带符号十进制整数
        //if (PLCCode.Length == 25)
        //{
        //    data = PLCCodeToStringData(PLCCode);
        //    string LWA = data[0];
        //    string RWA = data[1];
        //    LogMonitoringPage(LWA, RWA);         // 显示有效信息到监测界面

        //}
        //Log(LogMsgType.Incoming, PLCCode);      // 显示所有信息



有具体实现过程吗? --------------------编程问答--------------------
try
                {
                    comport.ReceivedBytesThreshold = comport.ReadBufferSize;
                    while (true)
                    {
                        strReceive = comport.ReadExisting();
                        if (string.Equals(strReceive, string.Empty))
                        {
                            break;
                        }
                        else
                        {
                            PLCCode += strReceive;
                            Application.DoEvents();
                            Thread.Sleep(100);
                        }
                    }
                    PLCCode = PLCCode.Replace("\0", string.Empty);    //去除非法符号,本例可以不要。
                    PLCCode = PLCCode.Replace("\r\n", string.Empty);
                    PLCCode = PLCCode.Replace("\r", string.Empty);
                    PLCCode = PLCCode.Replace("\n", string.Empty);


                    utPrint.Print(PLCCode);
                    //if (!this.bIsHandleCom)   //后台进程处理数据,需要学习
                    //{
                    //    this.bIsHandleCom = true;
                    //    mReceiveData = strCollect;
                    //    if (ReceiveDataParserEvent != null)
                    //        ReceiveDataParserEvent(mReceiveData);
                    //    if (ThreadReceiveParser != null && !ThreadReceiveParser.IsAlive)
                    //    {
                    //        ThreadReceiveParser.Start();
                    //    }
                    //}

                }
                catch (Exception ex)
                {
                    MessageBox.Show( ex.ToString(), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                finally
                {
                    comport.ReceivedBytesThreshold = 1;
                }
--------------------编程问答-------------------- 加数据校验,对应你的协议,分段解析数据 --------------------编程问答--------------------
引用 7 楼 yanping1988 的回复:
加数据校验,对应你的协议,分段解析数据


我们没有校验,只有数据包头和包尾,而且某一种指令得到的数据长度一定的(有很多指令,数据长度不一),每次都我都是把数据放到ArrayList数组中,先找头,然后找尾,如果找到了,就去处理,但数据经常丢一两个字节,不知道是在加入ArrayList数组时出错,还是什么原因 --------------------编程问答--------------------
引用 8 楼 youshoubian1 的回复:
Quote: 引用 7 楼 yanping1988 的回复:

加数据校验,对应你的协议,分段解析数据


我们没有校验,只有数据包头和包尾,而且某一种指令得到的数据长度一定的(有很多指令,数据长度不一),每次都我都是把数据放到ArrayList数组中,先找头,然后找尾,如果找到了,就去处理,但数据经常丢一两个字节,不知道是在加入ArrayList数组时出错,还是什么原因


看看你是怎么接收数据并加到ArrayList里的 --------------------编程问答-------------------- 我刚开始也是用的DataReceived事件和Threshold来设置阈值,但是DataReceived事件貌似是新开线程,我使用的总是会出现丢失字节的现象。后来我该用查询的方式,定个timer进行读取,读取里面的数据,判断数据。你可以试试 --------------------编程问答-------------------- 串口通讯,数据要一条一条发送。

也就是你客户端发到服务端时,最好有一条回应命令后,你客户端再发下一条命令。否则会出现过快,数据溢出。


还有,在循环发送这些数据时,是在线程里发送,每发一条,隔一点时间。100毫秒吧

我现在都是这样做的。从没出现问题 --------------------编程问答-------------------- 关于通讯这方面,如果没有好的机制,会出现堵包情况。 --------------------编程问答-------------------- 建议你用别人已经做好的串口工具来接收数据看看,看它是否也出现丢包或者丢字节。 --------------------编程问答-------------------- 根据我推断,很有可能是发过来的数据(本来一包数据)你这边接收到分为两包或者多包了,所以,你可能还要多加一步:组包。 --------------------编程问答--------------------
引用 14 楼 zhoumeiwen 的回复:
根据我推断,很有可能是发过来的数据(本来一包数据)你这边接收到分为两包或者多包了,所以,你可能还要多加一步:组包。


我是接过来后,放在arrlist中,然后判断,如果没达到要求,先是等待继续往arrlist中添加,最后如果数据不对,就会重发指令,目前经常会出现数据读不完,原因还在查找 --------------------编程问答--------------------
引用 11 楼 zhantianyou 的回复:
串口通讯,数据要一条一条发送。

也就是你客户端发到服务端时,最好有一条回应命令后,你客户端再发下一条命令。否则会出现过快,数据溢出。


还有,在循环发送这些数据时,是在线程里发送,每发一条,隔一点时间。100毫秒吧

我现在都是这样做的。从没出现问题
延时基本上可以解决问题,但数据量太大,延时会导致读取时间太长, --------------------编程问答--------------------
引用 9 楼 leafmao 的回复:
Quote: 引用 8 楼 youshoubian1 的回复:

Quote: 引用 7 楼 yanping1988 的回复:

加数据校验,对应你的协议,分段解析数据


我们没有校验,只有数据包头和包尾,而且某一种指令得到的数据长度一定的(有很多指令,数据长度不一),每次都我都是把数据放到ArrayList数组中,先找头,然后找尾,如果找到了,就去处理,但数据经常丢一两个字节,不知道是在加入ArrayList数组时出错,还是什么原因


看看你是怎么接收数据并加到ArrayList里的
我是一个字节就触发事件,然后int count =serialport.read(buffer,0,bytestoread),然后dispose(buffer) --------------------编程问答--------------------
引用 15 楼 youshoubian1 的回复:
Quote: 引用 14 楼 zhoumeiwen 的回复:

根据我推断,很有可能是发过来的数据(本来一包数据)你这边接收到分为两包或者多包了,所以,你可能还要多加一步:组包。


我是接过来后,放在arrlist中,然后判断,如果没达到要求,先是等待继续往arrlist中添加,最后如果数据不对,就会重发指令,目前经常会出现数据读不完,原因还在查找

建议是定义一个大一点的byte数组,接收到数据就往里面写,然后你再到byte数组里面去查找和做一些处理,处理完一个完整包就把那部分从byte数组里面移除 --------------------编程问答--------------------
引用 17 楼 youshoubian1 的回复:
Quote: 引用 9 楼 leafmao 的回复:

Quote: 引用 8 楼 youshoubian1 的回复:

Quote: 引用 7 楼 yanping1988 的回复:

加数据校验,对应你的协议,分段解析数据


我们没有校验,只有数据包头和包尾,而且某一种指令得到的数据长度一定的(有很多指令,数据长度不一),每次都我都是把数据放到ArrayList数组中,先找头,然后找尾,如果找到了,就去处理,但数据经常丢一两个字节,不知道是在加入ArrayList数组时出错,还是什么原因


看看你是怎么接收数据并加到ArrayList里的
我是一个字节就触发事件,然后int count =serialport.read(buffer,0,bytestoread),然后dispose(buffer)


得把buffer添加到ArrayList里,收到的每个字节都要加到ArrayList,然后去分析ArrayList --------------------编程问答-------------------- 其实很简单地,只要在设置好缓冲区,然后响应触法事件,判断缓冲区没有新的数据增加了,就开始解析数据,估计你数据没有接收全就开始解析了 --------------------编程问答--------------------
引用 20 楼 djc7811 的回复:
其实很简单地,只要在设置好缓冲区,然后响应触法事件,判断缓冲区没有新的数据增加了,就开始解析数据,估计你数据没有接收全就开始解析了

不同类型数据 长度不一样, --------------------编程问答--------------------
引用 19 楼 leafmao 的回复:
Quote: 引用 17 楼 youshoubian1 的回复:

Quote: 引用 9 楼 leafmao 的回复:

Quote: 引用 8 楼 youshoubian1 的回复:

Quote: 引用 7 楼 yanping1988 的回复:

加数据校验,对应你的协议,分段解析数据


我们没有校验,只有数据包头和包尾,而且某一种指令得到的数据长度一定的(有很多指令,数据长度不一),每次都我都是把数据放到ArrayList数组中,先找头,然后找尾,如果找到了,就去处理,但数据经常丢一两个字节,不知道是在加入ArrayList数组时出错,还是什么原因


看看你是怎么接收数据并加到ArrayList里的
我是一个字节就触发事件,然后int count =serialport.read(buffer,0,bytestoread),然后dispose(buffer)


得把buffer添加到ArrayList里,收到的每个字节都要加到ArrayList,然后去分析ArrayList


是的,我也是这么做的,但数据就是会丢的 --------------------编程问答--------------------
引用 21 楼 youshoubian1 的回复:
Quote: 引用 20 楼 djc7811 的回复:

其实很简单地,只要在设置好缓冲区,然后响应触法事件,判断缓冲区没有新的数据增加了,就开始解析数据,估计你数据没有接收全就开始解析了

不同类型数据 长度不一样,


晕,不是给你说了吗,判断缓冲区没有心的数据增加了,就读取并清空缓冲区,数据长度再长再短,类型再不一样哪有什么关系 --------------------编程问答-------------------- 代码又不肯贴,说数据丢失,让我们怎么猜。。。。
看看是不是数据传输太快,超出缓冲区的大小了 --------------------编程问答-------------------- 忘了贴代码了,明天补上,模块已经做的差不多了,就是想把延时去掉,明天贴代码
--------------------编程问答--------------------
找找之前的贴子呀。。
http://bbs.csdn.net/topics/390316188 字节缓冲区。。请看50楼。。 --------------------编程问答-------------------- 试一试把上位机程序的串口的DTR和RTS打开,再看一下还有没有丢数据情况
补充:.NET技术 ,  C#
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,