新手求助异步处理数据出现问题

qq_38812852 2017-05-25 09:07:33
private void RecvData()
{
while(bReceiving)
{
lock (this)
{
IAsyncResult iar = recvUdpClient.BeginReceive(new AsyncCallback(asycRecvCallback), udpRecvState);
recvDone.WaitOne();
Thread.Sleep(20);
}
}
}
private void asycRecvCallback(IAsyncResult iar)
{
UdpState udpState = iar.AsyncState as UdpState;
if (iar.IsCompleted)
{
byte[] recvBytes = udpState.udpclient.EndReceive(iar, ref udpRecvState.ipEndPoint);
string strRecv = ByteToString(recvBytes);
if (recvBytes.Length > 0)
{
this.RecvDataUnPacket(strRecv, recvBytes.Length);
}
recvDone.Set();
}
}

背景是上位机监管数十个节点采集信息,每个节点有二十个左右的参数配置,比如温度湿度等等.节点共用一个UI显示数据,点击不同的节点显示相应的数据信息,同时能查看不同节点的历史信息记录.
由于新手经验不足,做法是封装数据类,根据节点数目建立类对象。将解包后的数据根据ID先存入相应的类对象中,然后invoke UI更新当前节点的显示,并存储到数据库表单中。处理过程就是RecvDataUnPacket函数。
由于对异步和多线程概念比较模糊,这样接收到数据立即处理会不会影响效率?还是要再开线程?每个节点一秒钟发一次数据到上位机,每条数据长度为几百个字节。测试了一个节点数据。但是十几分钟过后程序崩溃提示:由于系统缓冲区空间不足或队列已满,不能执行套接字上的操作。 调试停留在了这里, IAsyncResult iar = recvUdpClient.BeginReceive(new AsyncCallback(asycRecvCallback), udpRecvState);求教大神该怎么做?谢谢
此外,不晓得Thread.Sleep(20)有什么作用,但是删除了以后就出问题了。
...全文
208 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
wang_peng_yl 2017-05-27
  • 打赏
  • 举报
回复
引用 5 楼 qq_38812852 的回复:
[quote=引用 3 楼 wang_peng_yl 的回复:] 我不太建议一楼的写法,不要跟风,追潮流,1楼的写法是新, java程序员习惯这样干,但它可读性差,调试费劲
那该怎么写啊,有例子么?处理更新存储过程全部放在this.RecvDataUnPacket中,现在提示缓冲区空间不足队列已满,这才一个节点跑了十来分钟而已。。都不知道怎么整了[/quote] 按你现在写的就没问题,看样子你不习惯写注释,所以只能用函数名去标注, 这也是以前那些老程序所提倡的
wang_peng_yl 2017-05-27
  • 打赏
  • 举报
回复
引用 11 楼 ilikeff8 的回复:
[quote=引用 3 楼 wang_peng_yl 的回复:] 我不太建议一楼的写法,不要跟风,追潮流,1楼的写法是新, java程序员习惯这样干,但它可读性差,调试费劲
这可不是跟风潮流,这已经不是什么新的写法了,出来很久了,是你不更新自己的知识 可读性一定都不差,匿名方法里的语句也可以设置断点,怎么就调试费劲了[/quote] 先说一下可读性,楼主的代码里一点点注释都没有,匿名习惯要是大面积应该,几个月后怕他自己都不知道是什么,更别说别人了 匿名, 它能代表什么,之前用asycRecvCallback,最起码从函数名就知道这个函数主要做什么的,也可以被其它函数用到 再说调试,你觉得不费劲,那是因为你习惯了,
ilikeff8 2017-05-26
  • 打赏
  • 举报
回复
引用 3 楼 wang_peng_yl 的回复:
我不太建议一楼的写法,不要跟风,追潮流,1楼的写法是新, java程序员习惯这样干,但它可读性差,调试费劲
这可不是跟风潮流,这已经不是什么新的写法了,出来很久了,是你不更新自己的知识 可读性一定都不差,匿名方法里的语句也可以设置断点,怎么就调试费劲了
qq_38812852 2017-05-26
  • 打赏
  • 举报
回复
引用 7 楼 sp1234 的回复:
异步 Receive 大致是类似这样的操作方式
public class MySession
{
    public ....... client;
    public List<byte> datas;

    public void StartReceive()
    {
        this.client.BeginReceive(asycRecvCallback, null); 
    }   

    private void asycRecvCallback(IAsyncResult iar)
        {
                byte[] recvBytes = this.client.EndReceive(iar, ........);
                datas.AddRange(recvBytes);
                var len = 判断datas中是否有一条完整的消息并返回其字节数();
                if(len>0)
                {
                     var command = GetYourString(datas, len);
                     将datas的前len个字节移除;
                     ThreadPool.QueueUserWorkitem(h=> 处理命令(command));
                }
                this.client.BeginReceive(asycRecvCallback, null); 
            }
        }
     
这里绝对没有什么 while 循环、WaitOne/Set 阻塞、ThreadSleep 阻塞之类的代码。
下午测试了三个小时还没发现什么问题,谢谢。结帖了
qq_38812852 2017-05-26
  • 打赏
  • 举报
回复
引用 8 楼 sp1234 的回复:
你使用了异步多线程处理的代码,却模拟一个同步阻塞的操作,那么你为什么不直接用
recvUdpClient.Receive
语句呢?为什么要学人家用什么 BeginReceive 呢?这种写法肯定是会让代码非常混乱的。 msdn 的这部分代码很垃圾,它只是说明了 BeginReceive 的语法而已,但是它显然是过于垃圾了。这里不要学 msdn。 异步操作设计,本来就是要减少不必要的资源浪费的(特别地,要充分释放线程占用),怎么可能会是 while+waitone+sleep 这种玩意儿的组合代码呢?
谢谢我试试
  • 打赏
  • 举报
回复
你使用了异步多线程处理的代码,却模拟一个同步阻塞的操作,那么你为什么不直接用
recvUdpClient.Receive
语句呢?为什么要学人家用什么 BeginReceive 呢?这种写法肯定是会让代码非常混乱的。 msdn 的这部分代码很垃圾,它只是说明了 BeginReceive 的语法而已,但是它显然是过于垃圾了。这里不要学 msdn。 异步操作设计,本来就是要减少不必要的资源浪费的(特别地,要充分释放线程占用),怎么可能会是 while+waitone+sleep 这种玩意儿的组合代码呢?
  • 打赏
  • 举报
回复
异步 Receive 大致是类似这样的操作方式
public class MySession
{
    public ....... client;
    public List<byte> datas;

    public void StartReceive()
    {
        this.client.BeginReceive(asycRecvCallback, null); 
    }   

    private void asycRecvCallback(IAsyncResult iar)
        {
                byte[] recvBytes = this.client.EndReceive(iar, ........);
                datas.AddRange(recvBytes);
                var len = 判断datas中是否有一条完整的消息并返回其字节数();
                if(len>0)
                {
                     var command = GetYourString(datas, len);
                     将datas的前len个字节移除;
                     ThreadPool.QueueUserWorkitem(h=> 处理命令(command));
                }
                this.client.BeginReceive(asycRecvCallback, null); 
            }
        }
     
这里绝对没有什么 while 循环、WaitOne/Set 阻塞、ThreadSleep 阻塞之类的代码。
qq_38812852 2017-05-26
  • 打赏
  • 举报
回复
引用 4 楼 oysy 的回复:
楼主不是会搞水质监测吧? 我这里有现成的上位机程序,是我自己写的 已经用于重庆水利局和重庆卫生局
不是水质监测啊。。工程经验太少,可以发给我学习下么?谢谢啦
qq_38812852 2017-05-26
  • 打赏
  • 举报
回复
引用 3 楼 wang_peng_yl 的回复:
我不太建议一楼的写法,不要跟风,追潮流,1楼的写法是新, java程序员习惯这样干,但它可读性差,调试费劲
那该怎么写啊,有例子么?处理更新存储过程全部放在this.RecvDataUnPacket中,现在提示缓冲区空间不足队列已满,这才一个节点跑了十来分钟而已。。都不知道怎么整了
飞天凤凰601 2017-05-26
  • 打赏
  • 举报
回复
楼主不是会搞水质监测吧? 我这里有现成的上位机程序,是我自己写的 已经用于重庆水利局和重庆卫生局
wang_peng_yl 2017-05-26
  • 打赏
  • 举报
回复
我不太建议一楼的写法,不要跟风,追潮流,1楼的写法是新, java程序员习惯这样干,但它可读性差,调试费劲
wang_peng_yl 2017-05-26
  • 打赏
  • 举报
回复
Thread.Sleep(20); 是为了防治假死, 不用的话CPU会一直高占用率
ilikeff8 2017-05-25
  • 打赏
  • 举报
回复
这种是老写法,写复杂了,直接用recvUdpClient.Receive,外面包个线程就可以了

        bool isStop = false;

        public Form1()
        {
            InitializeComponent();

            ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
            {
                while (!isStop)
                {
                     string data=Receive();

                    this.Invoke(new Action(() =>
                    {
                        this.Text = data;
                    }));
                }
            }));
        }

        string Receive()
        {
            Thread.Sleep(1000);
            return "模拟返回数据:" + DateTime.Now.ToString();
        }
    }

110,561

社区成员

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

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

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