ASP.Net串口Basestream阅读器

时间:2017-01-10 10:29:36

标签: c# .net

c#中的我的应用从串口读取整数(字符串" X\n")但是在发送30行开始发送1之后它无法正常工作带空格的-2位数。
这是buffor的东西吗?我尝试使用BaseStream.ReadAsync,但它会产生太多错误。我是新手程序员,所以请简单解释一下。

    SerialPort serialPort;
        private Action startReading;
        int bufferLength = 4096;

        public Form1()
        {
            InitializeComponent();
        }

        public bool Open()
        {
            serialPort = new SerialPort("COM4", 9600, Parity.None, 8, StopBits.One);
            bool result = false;
            try
            {

                this.serialPort.Open();
                result = true;
                startReading = StartAsyncSerialReading;
                startReading();
            }
            catch (Exception)
            {
                this.Close();
                result = false;
            }
            return result;

        }

        private void StartAsyncSerialReading()
        {
            byte[] buffer = new byte[bufferLength];

            serialPort.BaseStream.BeginRead(buffer, 0, bufferLength, delegate (IAsyncResult ar)
            {
                try
                {
                    if (serialPort.IsOpen)
                    {
                        int actualLength = serialPort.BaseStream.EndRead(ar);
                        byte[] received = new byte[actualLength];
                        Buffer.BlockCopy(buffer, 0, received, 0, actualLength);
                        string data = Encoding.ASCII.GetString(received, 0, actualLength);
                        Console.WriteLine(data);

                    }
                }

                catch (IOException exc)
                {
                    ## Heading ##
                }

                if (serialPort.IsOpen)
                    startReading();

            }, null);

        }
public void ClosePort()
        {
            this.serialPort.Close();
            this.serialPort.Dispose();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            ClosePort();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Open();
            StartAsyncSerialReading();
        }

2 个答案:

答案 0 :(得分:0)

尝试以下更改:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;

namespace WindowsFormsApplication22
{
    public partial class Form1 : Form
    {
        SerialPort serialPort;
        private Action startReading;
        int bufferLength = 4096;
        string data;

        public Form1()
        {
            InitializeComponent();
        }

        public bool Open()
        {
            serialPort = new SerialPort("COM4", 9600, Parity.None, 8, StopBits.One);
            bool result = false;
            try
            {

                this.serialPort.Open();
                result = true;
                startReading = StartAsyncSerialReading;
                startReading();
            }
            catch (Exception)
            {
                this.Close();
                result = false;
            }
            return result;

        }

        private void StartAsyncSerialReading()
        {
            byte[] buffer = new byte[bufferLength];

            serialPort.BaseStream.BeginRead(buffer, 0, bufferLength, delegate (IAsyncResult ar)
            {
                try
                {
                    if (serialPort.IsOpen)
                    {
                        int actualLength = serialPort.BaseStream.EndRead(ar);
                        byte[] received = new byte[actualLength];
                        Buffer.BlockCopy(buffer, 0, received, 0, actualLength);
                        data += Encoding.ASCII.GetString(received, 0, actualLength);
                        while (data.Contains("\n"))
                        {
                            string message = data.Substring(0, data.IndexOf("\n"));
                            Console.WriteLine(message);
                            //remove message from buffer
                            data = data.Substring(data.IndexOf("\n") + 1);
                        }

                    }
                }

                catch (IOException exc)
                {
                    //## Heading ##
                }

                if (serialPort.IsOpen)
                    startReading();

            }, null);

        }
        public void ClosePort()
        {
            this.serialPort.Close();
            this.serialPort.Dispose();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            ClosePort();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Open();
            StartAsyncSerialReading();
        }
    }
}

答案 1 :(得分:0)

首先,您的代码看起来不像Web服务代码,但您的标题和标签都说ASP.NET。如果你真的在ASP.NET中,那么就不可能进行串行I / O,你需要重新构建事物。 ASP是请求驱动的,当托管进程决定回收一个worker时你的对象会死掉,你可以同时拥有多个请求,这只是各种各样的不好。要使Web服务显示来自串行设备的数据,您需要一个后台服务充当代理 - 该服务打开串行端口并在数据到达时按顺序处理数据,然后ASP.NET页面获取数据来自后台服务的请求进来。

其次,根据您的.NET版本,使用BaseStream.ReadAsync代替BeginRead / EndRead。我的博客文章是在C#async / await成为主流之前编写的,因此它仍然显示较旧的方式。将awaitReadAsync一起使用,您的所有处理都会在您自己的线程上进行,这意味着事情永远不会按照BeginInvoke(在您的评论中看到)的方式进行。

接下来,虽然可以使用字符串缓冲数据jdweng在他的答案中显示的方式(如果你这样做,使用StringBuilder而不是一堆短命的字符串),这会导致它的一些问题拥有。使用ASCII字符集并不是那么糟糕,但在多字节编码中,如果串行读取在字符中间结束,您会怎么做?您需要使用有状态转换器。您当前的一些问题完全可能来自发送CR + LF的设备 - 如果这些问题单独添加到文本框中,则可能会导致两个换行符。总的来说,将初始处理(查找消息边界等)作为存储在字节数组中的普通二进制数据做得更好。在字节数组中搜索换行符并不像在StringBuilder中这样做那么简单,但也不难。

最后,你的协议很糟糕。 jdweng在关于在消息中间打开端口的评论中告诉你的所有事情,如果你使用适当的自同步协议同时使用start和stop分隔符或者开始分隔符,那么问题就不那么大了。和长度前缀。除非您的数据源以某种方式与打开端口时同步(例如,如果它正在等待您在开始发送之前发送命令 - 但我看不到代码中有任何传出命令的迹象)那么您您的数据流在消息中间启动的几率是不可忽略的。您的所有读取都可以在消息的中间开始或结束,第一个只是特别糟糕,因为您无法看到该消息的开头知道如何解释这些前几个字节。

如果您对协议有创造性的控制权,那么更改它会产生很大的不同。我总是使用唯一的起始字节(字节填充确保唯一性),长度字段,时间戳和强纠错代码。但是,我有解码这种格式的工具,所以拥有一个人类可读的协议对我来说并不重要。