代码:
static void Main(string[] args)
{
Console.WriteLine("Memory mapped file reader started");
using (var file = MemoryMappedFile.OpenExisting("AIDA64_SensorValues"))
{
using (var readerz = file.CreateViewAccessor(0, 0))
{
var bytes = new byte[567];
var encoding = Encoding.ASCII;
readerz.ReadArray<byte>(0, bytes, 0, bytes.Length);
File.WriteAllText("C:\\myFile.txt", encoding.GetString(bytes));
var readerSettings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment };
using (var reader = XmlReader.Create("C:\\myFile.txt", readerSettings))
{
while (reader.Read())
{
using (var fragmentReader = reader.ReadSubtree())
{
if (fragmentReader.Read())
{
reader.ReadToFollowing("value");
SerialPort port = new SerialPort("COM2", 9600, Parity.None, 8, StopBits.One);
port.Open();
port.Write(reader.ReadElementContentAsString() + ",");
}
}
}
}
}
}
Console.WriteLine("Press any key to exit ...");
Console.ReadLine();
}
它读取共享内存,将共享内存写入文件,然后使用xml reader打开同一文件并拆分xml,因为它有多个根,然后获取每个新拆分xml上的节点值并通过串行发送。它适用于第一个拆分xml,并且其节点通过串行发送然后停止,并且在尝试将第二个节点写入串行时拒绝访问com端口消息。
我有另一个应用程序,我使用相同的序列代码,它工作正常(我只是累了它然后关闭它。)...所以它很奇怪。
答案 0 :(得分:25)
您只能打开一次串口。但是你的代码在while循环中有Open()调用。这只适用于第一次通过循环,kaboom在第二次传球。 @ cdhowie的解决方案也不起作用,SerialPort有一个文档警告的怪癖(也就是bug)。在Dispose()或Close()调用之后,需要时间让工作线程退出。时间量未指定且不可预测。
真正的解决方案很简单,只需在while循环之前移动Open()调用。
答案 1 :(得分:3)
除了Hans&#39;回答:
我遇到了同样的问题,在打开和关闭串口之间有一些睡眠时间。在我的情况下250毫秒就足够了。 也许这会帮助那里的人。
编辑:
我优化了我的解决方案,这就是我想出来的:
int maxRetries = 20;
const int sleepTimeInMs = 50;
string loggingMessage = string.Empty;
while (maxRetries > 0)
{
try
{
loggingMessage = "Opening serial port '" + mSerialPort.PortName + "'...";
mSerialPort.Open();
loggingMessage += "Succeeded.";
IOLogger.LogInfo(loggingMessage);
}
catch (UnauthorizedAccessException unauthorizedAccessException)
{
maxRetries--;
loggingMessage += "Failed (UnauthorizedAccessException): ";
IOLogger.LogError(string.Format(loggingMessage + unauthorizedAccessException.Message + " -> Retrying in about {0} milliseconds...", sleepTimeInMs));
Thread.Sleep(sleepTimeInMs);
}
catch (Exception exception)
{
loggingMessage += "Failed: ";
IOLogger.LogError(loggingMessage + exception.Message);
}
}
您可以使用sleepTimeInMs
和/或maxRetries
。
我选择了这些值,因为它们似乎足以满足任何需要的用例。
答案 2 :(得分:0)
汉斯的回答取代了这一个;我将其留作上下文和仅供参考。
完成后,您需要关闭端口。在您尝试打开另一个句柄之前,垃圾收集器不会收集第一个SerialPort
对象。更改此代码:
SerialPort port = new SerialPort("COM2", 9600, Parity.None, 8, StopBits.One);
port.Open();
port.Write(reader.ReadElementContentAsString() + ",");
要:
using (SerialPort port = new SerialPort("COM2", 9600, Parity.None, 8, StopBits.One)))
{
port.Open();
port.Write(reader.ReadElementContentAsString() + ",");
}
答案 3 :(得分:0)
对我有用的解决方案如下: 1:使用try catch块并将所有打开和关闭端口的代码放入其中。
2:使用IsOpen()函数检查端口是否已打开。
3:如果发生任何异常(访问被拒绝),请在catch块中写入Port.Close()代码以释放该端口。
4:在尝试捕获块使其通用之前,先使串行端口成为对象。
5:Open()调用不应位于循环内部。您应该只打开一次端口,然后在循环之后关闭它。
如果按照所有这些步骤操作,您将永远不会再遇到此问题。
下面给出了示例代码:
GsmCommMain comm = new GsmCommMain(COMPort.ToString(), 9600, 500);
try{ for (int i = 0; i < dtObj.Rows.Count; i++)
{
if (dtObj.Rows[i]["smsNumber"] != null)
{
if (dtObj.Rows[i]["smsNumber"].ToString() != "")
{
if (dtObj.Rows[i]["status"].ToString() != "Sent")
{
Thread.Sleep(Convert.ToInt32("50000"));
string txtMessage = dtObj.Rows[i]["sms"].ToString();
string txtDestinationNumbers = dtObj.Rows[i]["smsNumber"].ToString();
bool unicode = true;
SmsSubmitPdu[] pdu = SmartMessageFactory.CreateConcatTextMessage(txtMessage, unicode, txtDestinationNumbers);
comm.SendMessages(pdu);
obj_bal_ForAll.bal_forAll_Delete("tbl_SMS", "smsId", dtObj.Rows[i]["smsId"].ToString());
}
}
}
}
if (comm.IsOpen())
{
comm.Close();
}
}catch(Exception ex){if (comm.IsOpen()){comm.Close();}}
答案 4 :(得分:0)
如果端口未打开,则需要关闭并处置该端口,因为该端口未放置在最后一个连接处。