串口接收,原本用事件触发,问题没有解决掉
现在换成线程方式接收,还是存在要拼包的问题,请大神指导呀发送命令:
 comm.Write(cmds, 0, cmds.Length);
////记录发送的字节数
 n = cmds.Length;
 send_count += n;//累加发送字节数
 labelSendCount.Text = "Send:" + send_count.ToString();//更新界面  revcThread = new Thread(new ThreadStart(revc));//定义接收线程
  revcThread.Start();//开始接收线程
接收ARM返回的数据包,目前未做解析工作,,现在是接到什么数据,就直接显示在一个文本框内
private void revc()
        {
            string str = "";            
            int n = comm.BytesToRead;
            byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据
            received_count += n;//增加接收计数           
            comm.Read(buf, 0, n);//读取缓冲数据             this.Invoke((EventHandler)(delegate
            {
                for (int i = 0; i < n; i++)
                {
                    str += buf[i].ToString("X2");
                }
                this.txGet.AppendText(str+"\r\n");               
                //修改接收计数
                labelGetCount.Text = "Get:" + received_count.ToString();
            }));           
            revcThread.Abort();
        }
ARM 返回的数据格式如下
F0037E018E (这句是告诉上位机,ARM已经接收到数据了)
70011701060000FFFF0144444444444444444444444442
70011701060000FFFF01666666666666666666666666AA
70011701060000FFFF0155555555555555555555555576
...N条(7001打头的数据)
F0037E048B(这个句是告诉,上位机,ARM已经成功处理,并成功返回了N条记录)F0 打头的数据包,
 F0 代表引导码
 03 代表本包长度
 7E 04 数据内容
 8B 代表校验
7001 打头的数据包,,是真正记录的内容数据包7001 17 01060000FFFF01555555555555555555555555 767001 引导码
17 代表本条记录的总长度
中间为记录内容
最后的 76 代表校验和现在用线程方式,接收串口返回包,依然存在要拼包的问题 我发送命令给ARM后,开始返回数据,想F0或7001打头的数据包,从ARM上虽然是一个包一个包,向外打数据,如:
    F0037E018E  作为一个包发送
   7001.......checksum(一个字节校验和), 每个7001 打头的数据包,也是作为一个条件记录打到串口。但是 C#的线程里接收时,,发现他们还是粘帖在一起的
  仍是不是想象中的,一个包一个包过来的
  
而是像下面这样一起过来的:   F0037E018E70011701060000FFFF01555555555555555555555555xxxxxxxx76 假设我接收时,数组大小 256, 而刚好0701打头的数据包也是256字节
 则把7001打头的数据包,丢掉了5个字节(因为  F0037E018E 这个包占掉了5个)
 
 这样 就是不是一个完整的数据包了 请高手指点一下,最好能有简单的那种代码示范 呵呵
 谢谢
 
 

解决方案 »

  1.   

    无论网络多稳定,终究是不稳定的。。包头定义长度,自己解包吧。。
    我以前做的socket Windows Services,很少出现粘包情况,后来换了网络环境。。
    经常粘包,最后还是自己通过定义数据长度解析了,问题解决。
      

  2.   

    我这个串口 一次收不齐呢,,本来一个完整的包就被打乱了刚查了一点资料,,貌似ArrayList 这样可以吧
      

  3.   


            public static void Main(string[] args)
            {
                SerialPort comm;
                //.............
                ThreadPool.QueueUserWorkItem(recv, comm);
                while (true)
                {
                    string s = Console.ReadLine();
                    comm.WriteLine(s);
                }
            }
            static void recv(object obj)
            {
                SerialPort comm = (SerialPort)obj;
                byte[] buffer = new byte[256];
                int offset = 0;
                int count = 4;
                while (true)
                {
                    int recvlen = comm.Read(buffer, offset, count);
                    if (recvlen != count)
                    {
                        offset += recvlen;
                        count -= recvlen;
                        continue;
                    }
                    if (offset < 4)
                    {
                        if (buffer[0] == 0xf0)
                        {
                            offset = 4;
                            count = buffer[1];
                            continue;
                        }
                        if (buffer[0] == 0x70)
                        {
                            offset = 4;
                            count = 1;
                            continue;
                        }
                    }
                    if (offset < 6)
                    {
                        offset = 6;
                        count = buffer[2] - 3;
                        continue;
                    }
                    int len = 0;
                    if (buffer[0] == 0xf0)
                        len = 2 + buffer[1];
                    else
                        len = buffer[2];
                    //显示buffer从0到len的内容
                    offset = 0;
                    count = 4;
                }
            }
      

  4.   

    不好意思,上面的4和6是错误的,改为2和3        public static void Main(string[] args)
            {
                SerialPort comm;
                //.............
                ThreadPool.QueueUserWorkItem(recv, comm);
                while (true)
                {
                    string s = Console.ReadLine();
                    comm.WriteLine(s);
                }
            }
            static void recv(object obj)
            {
                SerialPort comm = (SerialPort)obj;
                byte[] buffer = new byte[256];
                int offset = 0;
                int count = 2;
                while (true)
                {
                    int recvlen = comm.Read(buffer, offset, count);
                    if (recvlen != count)
                    {
                        offset += recvlen;
                        count -= recvlen;
                        continue;
                    }
                    if (offset < 2)
                    {
                        if (buffer[0] == 0xf0)
                        {
                            offset = 2;
                            count = buffer[1];
                            continue;
                        }
                        if (buffer[0] == 0x70)
                        {
                            offset = 2;
                            count = 1;
                            continue;
                        }
                    }
                    if (offset < 3)
                    {
                        offset = 3;
                        count = buffer[2] - 3;
                        continue;
                    }
                    int len = 0;
                    if (buffer[0] == 0xf0)
                        len = 2 + buffer[1];
                    else
                        len = buffer[2];
                    //显示buffer从0到len的内容
                    offset = 0;
                    count = 2;
                }
            }
      

  5.   


     if (offset < 3)
                    {
                        offset = 3;
                        count = buffer[2] - 3;
                        continue;
                    }
                    int len = 0;
                    if (buffer[0] == 0xf0)
                        len = 2 + buffer[1];
                    else
                        len = buffer[2];
                    //显示buffer从0到len的内容
                    offset = 0;
                    count = 2;这段没看明白啥意思 还有这句
      
     ThreadPool.QueueUserWorkItem(recv, comm);
      

  6.   

    先说ThreadPool.QueueUserWorkItem(recv, comm);这个是使用系统线程池的线程,和用new Thread一样,但建议涉及到线程的尽量使用系统线程池。
    整个流程是这样的,读取线程除非意外或者其他情况,不需要退出,因此里面用一个while来不断读取内容。
    读取时需要分包,那就需要offset和count来控制。循环的初始,先读取两个字节,判断是什么通过第一个字节判断是什么类型的数据,如果是0xf0,那么第二个字节就是本包长度,根据这个长度再读取后面的本包内容。如果是0x70,那么本报长度在第三个字节上,因此在读取一个字节获取长度,获取后再根据长度读取剩余的本包内容。
    为了保证在界面处理每一个包时,buffer里面的包内容都完整且不冗余,就要依靠offset的递增和count的递减来读取,直至希望读取的长度count等于实际读取的长度recvlen。为什么要判断offset < 2和offset < 3,因为有两次分别是期望读取2个字节和3个字节,在这两种情况之外,就是读取到了一个完整的包。因为此时offset和count已经发生了数次变化,所以要通过判断包的类型来得到包的长度,然后将其显示到界面上。
    在处理完一个完整的包之后,要将offset和count重置为0,2,以读取下一个包。
      

  7.   

    SerialPort comm;
                //.............
                ThreadPool.QueueUserWorkItem(recv, comm);这两句有问题 无论是放formload 里,还是 Button Click 里 都在第二句提示: 使用了未复制到变量 SerialPort comm=NULL ; 不报错了 但是,到了 接收线程里有出问题了
    while (true)
                {
                    int recvlen = comm.Read(buffer, offset, count);
    // 提示串口关闭,无法读写数据
      

  8.   

     //.............
    我的中间有上面这个,这个意思是你根据你的程序写comm初始化和open的一系列内容。
    其实我有一个疑问,0xf0打头的那个数据包后面的0x03到底代表本包剩余长度还是后面的数据的条数,如果是后者,那我的这个伪代码需要修改。
      

  9.   

     是这样的
     
     ARM 返回的数据格式如下
    F0037E018E (这句是告诉上位机,ARM已经接收到数据了,其实无意义,
    即,可以不处理,)真正有意义的数据是 7001 打头的数据70011701060000FFFF0144444444444444444444444442
    70011701060000FFFF01666666666666666666666666AA
    70011701060000FFFF0155555555555555555555555576
    ...N条(7001打头的数据)F0037E048B(这个句是告诉,上位机,ARM已经成功处理,并成功返回了N条记录)N条的 7001 打头的数据,才是真正要的数据包,如下
    7001     17               01060000FFFF01555555555555555555555555  76
    引导码   本条记录长度     01开始这14个字节才是要的数据            最后76是校验和
    主要问题就是 7001 打头的数据是直接跟在 F0打头的数据包后面 另外7001 打头的数据长度也是不固定,如 上面的长度目前是17,,有时可能是
      最小是5 ,..... 最大不会超过252 因此也会导致,,7001 Len xxxxxxxx sum7001 len xxxxxsum.... 这样粘这出现 自己也在看queue 的资料, 因为有人提到队列了,抓瞎中   
      

  10.   

    不要被口诀误导,那样会迷失方向。
    分包就是两种办法,第一种,接收时就分包,就是我这样;第二种,都放到大缓冲区,然后一个线程分析缓冲区。第一种清晰明快,每次处理的必定是完整且不冗余的包。
    为什么我觉得那个03很关键,因为我的伪代码中,把它理解为0xf0打头的包的剩余长度,就是按它来接收和分包的。如果0xf0打头的是固定的五个字节,那么就是另一种写法了。0x70打头的长度实际是多少就会按多少来分,因为对这个类型的包是根据第三个字节判断长度来接收的。
      

  11.   

    还有一个问题就是 
     F0 LEN XXXX
     7001 LEN 
    这两个引导码后面的长度也不是一个意思 F0 后面的长度代表,,LEN 后面的数据的长度 7001 后面的LEN ,,代表的是 从7001 len xxxx sum,整个包的长度
      

  12.   


    1、 FO 后面的 03,,是F0 03 7E 01 8E 这个包的长度
     
       接着就是想要的数据包了,7001 打头的  且在PC 发一次命令,并在 两个F0打头的包中间
      会出现N次 7001 打头的数据包我先试试 非常感谢
      

  13.   


    if (offset < 3)
                    {
                        offset = 3;
                        //count = buffer[2] - 3;
                        count = buffer[1] - 3;
                        continue;
                    } 我调试看了下,,这地放有点问题,,,就是计算 F0 或7001 后面的应该收多少的时候,
     目前 收F0 正常 而 7001 引导的时候,,要用被注释掉的那行才正常
     要不地址计算错了 非常感谢,,我再测试测试 呵呵