问题描述
我有一些 SerialPort 代码经常需要从串行接口(例如 COM1)读取数据.但这似乎是 CPU 密集型的,如果用户移动窗口或向窗口显示大量数据(例如通过串行线路接收的字节),那么通信就会混乱.
I have some SerialPort code that constantly needs to read data from a serial interface (for example COM1). But this seems to be very CPU intensive and if the user moves the window or a lot of data is being displayed to the window (such as the bytes that are received over the serial line) then communication gets messed up.
考虑以下代码:
void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte[] buffer = new byte[port.ReadBufferSize];
var count = 0;
try
{
count = port.Read(buffer, 0, buffer.Length);
}
catch (Exception ex)
{
Console.Write(ex.ToString());
}
if (count == 0)
return;
//Pass the data to the IDataCollector, if response != null an entire frame has been received
var response = collector.Collect(buffer.GetSubByteArray(0, count));
if (response != null)
{
this.OnDataReceived(response);
}
需要收集代码,因为数据流是恒定的并且必须针对(帧/数据包)分析数据.
The code needs to be collected as the stream of data is constant and the data has to be analyzed for (frames/packets).
port = new SerialPort();
//Port configuration code here...
this.collector = dataCollector;
//Event handlers
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
port.Open();
如果没有用户交互并且没有任何内容添加到窗口中,这很好用,但是一旦有交互,沟通就会变得一团糟.发生超时等......
If there is no user interaction and nothing being added to the window, this works fine but as soon as there is interaction communication really gets messed up. Timeouts occur etc....
例如,这会搞砸一切:
Dispatcher.BeginInvoke(new Action(() =>
{
var builder = new StringBuilder();
foreach (var r in data)
{
builder.AppendFormat("0x{0:X} ", r);
}
builder.Append("
");
txtHexDump.AppendText(builder.ToString());
txtHexDump.ScrollToEnd();
}),System.Windows.Threading.DispatcherPriority.ContextIdle);
});
但即使是对 log4net 的简单调用也会导致问题.
But even simple calls to log4net cause problems.
是否有优化 SerialPort 通信的最佳实践或者有人可以告诉我我做错了什么......
Are there any best practices to optimize SerialPort communication or can someone tell me what I'm doing wrong...
更新:
如果以上没有多大意义.我做了一个非常简单(也很愚蠢)的小例子:
In case the above didn't make much sence. I made a very simple (and stupid) little example:
class Program
{
static void Main(string[] args)
{
var server = new BackgroundWorker();
server.DoWork += new DoWorkEventHandler(server_DoWork);
server.RunWorkerAsync();
var port = new SerialPort();
port.PortName = "COM2";
port.Open();
string input = "";
Console.WriteLine("Client on COM2: {0}", Thread.CurrentThread.ManagedThreadId);
while (input != "/quit")
{
input = Console.ReadLine();
if (input != "/quit")
{
var data = ASCIIEncoding.ASCII.GetBytes(input);
port.Write(data, 0, data.Length);
}
}
port.Close();
port.Dispose();
}
static void server_DoWork(object sender, DoWorkEventArgs e)
{
Console.WriteLine("Listening on COM1: {0}", Thread.CurrentThread.ManagedThreadId);
var port = new SerialPort();
port.PortName = "COM1";
port.Open();
port.ReceivedBytesThreshold = 15;
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
}
static void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var port = (SerialPort)sender;
int count = 0;
byte[] buffer = new byte[port.ReadBufferSize];
count = ((SerialPort)sender).Read(buffer, 0, buffer.Length);
string echo = ASCIIEncoding.ASCII.GetString(buffer,0,count);
Console.WriteLine("-->{1} {0}", echo, Thread.CurrentThread.ManagedThreadId);
}
}
结果可能如下所示:
在 COM1 上监听:6COM2 上的客户端:10这是我发送的一些示例数据---> 6 这是我发送的一些示例数据
Listening on COM1: 6 Client on COM2: 10 This is some sample data that I send ---> 6 This is some sample data that I send
所以从端口读取数据发生在主线程上......
So reading the data from the port happens on the main thread....
这可能是导致我的问题的部分原因吗?
Might this be part of what's causing my problems?
推荐答案
您的最后一个结论,即事件在主线程上运行,可能不适用于 Windows 应用程序.不要在控制台中测试.
Your last conclusion, that the event runs on the Main thread, may not be true for Windows App. Don't test this in a Console.
调整这个的正确方法是:
The proper way to tune this is:
设置足够大的缓冲区,虽然通常最小4096就可以了
set a large enough buffer, although the minimum 4096 is usually Ok
将 ReceivedBytesThreshold 设置为可容忍的最高值(并在 Open() 之前执行此操作)
set the ReceivedBytesThreshold as high as tolerable (and do it before the Open())
在 Received 事件中尽量少做,通过如果您需要更多时间,可以将数据发送到队列或 MemoryStream
do as little as possible in the Received event, pass the data to a Queue or MemoryStream if you need more time
这篇关于System.IO.Ports.SerialPort 和多线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!