web-dev-qa-db-fra.com

pourquoi l'accès au port est-il refusé?

le code:

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

il lit la mémoire partagée, écrit cette mémoire partagée dans un fichier, puis le même fichier est ouvert avec un lecteur xml et scinde xml car il possède plusieurs racines, puis obtient la valeur d'un nœud sur chaque nouveau fichier xml divisé et l'envoie en série. il fonctionne sur le premier xml divisé et son nœud est envoyé en série, puis s'arrête avec un accès refusé au message de port com lors d'une tentative d'écriture du deuxième nœud en série.

j'ai une autre application que j'ai faite avec le même code de série et cela fonctionne très bien (je suis juste fatigué puis fermé.) ... donc c'est étrange.

11
Csharpz

Vous pouvez ouvrir un port série une seule fois. Mais votre code a l'appel Open () dans la boucle while. Cela ne fonctionnera que pour le premier passage dans la boucle, kaboom lors du deuxième passage. La solution de @ cdhowie ne fonctionne pas non plus, SerialPort a une bizarrerie (ou bogue) que la documentation met en garde. Il faut du temps pour laisser un thread de travail sortir après l'appel Dispose () ou Close (). La quantité de temps est indéterminée et imprévisible.

La vraie solution est simple, il suffit de déplacer l'appel Open () avant la boucle while.

25
Hans Passant

En plus de la réponse de Hans:

J'ai eu le même problème et joué un peu avec quelques temps de sommeil entre l'ouverture et la fermeture du port série. Dans mon cas, 250 ms suffisaient. Cela aidera peut-être quelqu'un.

MODIFIER:

J'ai optimisé ma solution et voici ce que j'ai proposé:

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

Vous pouvez jouer avec la sleepTimeInMs et/ou la maxRetries. J'ai choisi ces valeurs parce qu'elles semblaient suffisantes dans tous les cas d'utilisation nécessaires.

3
M. Hartner

La réponse de Hans remplace celle-ci; Je le quitte pour des raisons de contexte et d'information uniquement.


Vous devez fermer le port lorsque vous avez terminé. Le ramasse-miettes ne collecte pas le premier objet SerialPort avant d'essayer d'ouvrir un autre descripteur. Changer ce code:

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() + ",");
}
0
cdhowie