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();
}
答案 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
成为主流之前编写的,因此它仍然显示较旧的方式。将await
与ReadAsync
一起使用,您的所有处理都会在您自己的线程上进行,这意味着事情永远不会按照BeginInvoke
(在您的评论中看到)的方式进行。
接下来,虽然可以使用字符串缓冲数据jdweng在他的答案中显示的方式(如果你这样做,使用StringBuilder
而不是一堆短命的字符串),这会导致它的一些问题拥有。使用ASCII字符集并不是那么糟糕,但在多字节编码中,如果串行读取在字符中间结束,您会怎么做?您需要使用有状态转换器。您当前的一些问题完全可能来自发送CR + LF的设备 - 如果这些问题单独添加到文本框中,则可能会导致两个换行符。总的来说,将初始处理(查找消息边界等)作为存储在字节数组中的普通二进制数据做得更好。在字节数组中搜索换行符并不像在StringBuilder
中这样做那么简单,但也不难。
最后,你的协议很糟糕。 jdweng在关于在消息中间打开端口的评论中告诉你的所有事情,如果你使用适当的自同步协议同时使用start和stop分隔符或者开始分隔符,那么问题就不那么大了。和长度前缀。除非您的数据源以某种方式与打开端口时同步(例如,如果它正在等待您在开始发送之前发送命令 - 但我看不到代码中有任何传出命令的迹象)那么您您的数据流在消息中间启动的几率是不可忽略的。您的所有读取都可以在消息的中间开始或结束,第一个只是特别糟糕,因为您无法看到该消息的开头知道如何解释这些前几个字节。
如果您对协议有创造性的控制权,那么更改它会产生很大的不同。我总是使用唯一的起始字节(字节填充确保唯一性),长度字段,时间戳和强纠错代码。但是,我有解码这种格式的工具,所以拥有一个人类可读的协议对我来说并不重要。