簡體   English   中英

為什么訪問 com 端口被拒絕?

[英]why is access to com port denied?

代碼:

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 讀取器打開同一個文件並拆分 xml,因為它有多個根,然后獲取每個新拆分 xml 上的節點值並通過串行發送。 它適用於第一個拆分的 xml,它的節點通過串行發送,然后它停止並在嘗試將第二個節點寫入串行時拒絕訪問 com 端口消息。

我有另一個使用相同序列代碼制作的應用程序,它運行良好(我只是累了然后關閉了它。)...所以很奇怪。

您只能打開一個串行端口一次。 但是您的代碼在 while 循環中具有 Open() 調用。 這僅適用於第一次通過循環,第二次通過的 kaboom。 @cdhowie 的解決方案也不起作用,SerialPort 有一個文檔警告的怪癖(又名錯誤)。 在 Dispose() 或 Close() 調用之后讓工作線程退出需要時間。 時間量是未指定和不可預測的。

真正的解決方案很簡單,只需在 while 循環之前移動 Open() 調用即可。

除了漢斯的回答:

我遇到了同樣的問題,在打開和關閉串行端口之間有一些睡眠時間。 在我的情況下,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 我選擇這些值是因為它們在任何需要的用例中似乎都足夠了。

如果端口打開,您需要關閉並處理它,因為他沒有在最后一次連接時處理。

對我有用的解決方案如下: 1:使用try catch塊並將打開和關閉端口的所有代碼放入其中。

2:使用 IsOpen() 函數檢查端口是否已經打開。

3:如果發生任何異常(訪問被拒絕),請在 catch 塊中寫入 Port.Close() 代碼以釋放該端口。

4:在try catch塊之前先制作串口對象,使其通用。

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();}}

漢斯的回答取代了這一回答; 我將其僅用於上下文和信息目的。


完成后,您需要關閉該端口。 在您嘗試打開另一個句柄之前,垃圾收集器不會收集第一個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() + ",");
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM