Comment utiliser correctement .NET2.0 port série .BaseStream pour l'opération asynchrone
Je suis tenter de l'utiliser .BaseStream propriété de l' .NET2.0 SerialPort faire asynchrone lit et écrit (méthodes beginwrite/EndWrite, BeginRead/EndRead).
Je vais avoir quelques succès dans ce, mais après un certain temps, j'ai remarqué (à l'aide de l'Explorateur de Processus) une augmentation progressive dans les Poignées de l'application est à l'aide de, et, occasionnellement, un fil supplémentaire, ce qui augmente aussi le nombre de handles.
Le changement de contexte de taux augmente également chaque fois qu'un nouveau fil apparaît.
L'application envoie sans cesse de 3 octets à un AUTOMATE appareil, et obtient de 800 octets en retour, et à un taux de transmission de 57600.
La première CSwitch Delta (encore une fois, à partir de l'Explorateur de Processus) est de l'ordre de 2 500, ce qui semble très élevé, de toute façon. Chaque fois qu'un nouveau fil apparaît, l'augmentation de cette valeur, et la charge CPU augmente en conséquence.
Je suis en espérant que quelqu'un pourrait faire quelque chose de similaire, et peut m'aider, ou même de dire " Au nom de Dieu, de ne pas le faire de cette façon.'
Dans le code ci-dessous, " cela._stream " est obtenue à partir SerialPort.BaseStream, et CommsResponse est une classe que j'utilise comme IAsyncresult d'état de l'objet.
Ce code est commun à une connexion TCP que je fais comme une alternative à l'utilisation du port série, (j'ai un CommsChannel de la classe de base, avec un numéro de série et TCP canal dérivé) et qu'il n'en a aucun de ces problèmes, donc je suis raisonnablement optimiste qu'il n'y a rien de mal avec le CommsResponse classe.
Toutes les observations reçues avec reconnaissance.
///<summary>
///Write byte data to the channel.
///</summary>
///<param name="bytes">The byte array to write.</param>
private void Write(byte[] bytes)
{
try
{
//Write the data to the port asynchronously.
this._stream.BeginWrite(bytes, 0, bytes.Length, new AsyncCallback(this.WriteCallback), null);
}
catch (IOException ex)
{
//Do stuff.
}
catch (ObjectDisposedException ex)
{
//Do stuff.
}
}
///<summary>
///Asynchronous write callback operation.
///</summary>
private void WriteCallback(IAsyncResult ar)
{
bool writeSuccess = false;
try
{
this._stream.EndWrite(ar);
writeSuccess = true;
}
catch (IOException ex)
{
//Do stuff.
}
//If the write operation completed sucessfully, start the read process.
if (writeSuccess) { this.Read(); }
}
///<summary>
///Read byte data from the channel.
///</summary>
private void Read()
{
try
{
//Create new comms response state object.
CommsResponse response = new CommsResponse();
//Begin the asynchronous read process to get response.
this._stream.BeginRead(this._readBuffer, 0, this._readBuffer.Length, new AsyncCallback(this.ReadCallback), response);
}
catch (IOException ex)
{
//Do stuff.
}
catch (ObjectDisposedException ex)
{
//Do stuff.
}
}
///<summary>
///Asynchronous read callback operation.
///</summary>
private void ReadCallback(IAsyncResult ar)
{
//Retrieve the comms response object.
CommsResponse response = (CommsResponse)ar.AsyncState;
try
{
//Call EndRead to complete call made by BeginRead.
//At this point, new data will be in this._readbuffer.
int numBytesRead = this._stream.EndRead(ar);
if (numBytesRead > 0)
{
//Create byte array to hold newly received bytes.
byte[] rcvdBytes = new byte[numBytesRead];
//Copy received bytes from read buffer to temp byte array
Buffer.BlockCopy(this._readBuffer, 0, rcvdBytes, 0, numBytesRead);
//Append received bytes to the response data byte list.
response.AppendBytes(rcvdBytes);
//Check received bytes for a correct response.
CheckResult result = response.CheckBytes();
switch (result)
{
case CheckResult.Incomplete: //Correct response not yet received.
if (!this._cancelComm)
{
this._stream.BeginRead(this._readBuffer, 0, this._readBuffer.Length,
new AsyncCallback(this.ReadCallback), response);
}
break;
case CheckResult.Correct: //Raise event if complete response received.
this.OnCommResponseEvent(response);
break;
case CheckResult.Invalid: //Incorrect response
//Do stuff.
break;
default: //Unknown response
//Do stuff.
break;
}
}
else
{
//Do stuff.
}
}
catch (IOException ex)
{
//Do stuff.
}
catch (ObjectDisposedException ex)
{
//Do stuff.
}
}
OriginalL'auteur Andy | 2009-01-20
Vous devez vous connecter pour publier un commentaire.
Quelques suggestions:
Puisque vous êtes seulement envoyer 3 octets, vous pourriez avoir une synchrones Opération d'Écriture. Le retard ne sera pas un problème.
Également de ne pas créer un nouveau AsyncCallback tout le temps. Créer une Lecture et une Écriture AsyncCallback et de l'utiliser dans tous commencer à appeler.
OriginalL'auteur kgiannakakis
Aucun besoin de méthodes beginwrite. Vous ne envoyer 3 octets, ils entrent facilement dans la mémoire tampon de transmission, et vous êtes toujours sûr que le tampon est vide lorsque vous envoyer la prochaine série.
Gardez à l'esprit que les ports série sont beaucoup plus lentes que les connexions TCP/IP. Il est assez probable que vous vous retrouvez l'appel BeginRead() pour chaque octet que vous recevez. Que donne le pool de threads une bonne séance d'entraînement, vous auriez certainement voir beaucoup de changements de contexte. Pas si sûr au sujet de la poignée de la consommation. Assurez-vous de vérifier que, sans le débogueur.
Essayer DataReceived au lieu de BeginRead() est certainement quelque chose que vous devriez essayer. Tirer au lieu de pousser, vous allez utiliser un pool de threads thread quand il y a quelque chose qui se passe au lieu de toujours avoir un actif.
Comme Andy a dit,
BeginRead
/EndRead
permet de gérer facilement plusieurs octets par appel (en fonction du paramètre de délai d'attente). Et S. IO.P.SerialPort bloque un pool de threads thread en tout temps afin de détecter les données et le feu DataReceived, de sorte que vous êtes en imaginant la baisse de l'utilisation des ressources. En réalité, il y a moins de noyau d'appels nécessaires pourBeginRead
/EndRead
qu'avec la détection de l'activité-puis-lire la solution.OriginalL'auteur Hans Passant
Est-il possible de prendre les données à venir à partir du port série et l'envoyer directement à un fichier? Au haut d'un taux de transmission (1 MegaBaud) il est difficile de gérer cette quantité de non-stop de données.
OriginalL'auteur
Est la réponse de l'appareil toujours une taille fixe? Si oui, essayez d'utiliser
SerialPort.Lire
et de passer de la taille des paquets. Cela va bloquer, donc le combiner avecDataReceived
. Mieux encore, si la réponse se termine toujours avec le même personnage(s), et à cette fin la signature est unique dans le paquet, jeu de laSaut de ligne
de la propriété et de l'utilisationReadLine
. Cela permettra de vous vacciner contre l'avenir de la taille de paquet de changements.La poisse. Alors, comment savez-vous quand vous avez reçu un paquet complet?
Le paquet contient les en-tête et le terminateur octets, avec une longueur de paquet et de la somme de contrôle codées à l'intérieur d'elle.
Si la terminaison est garantie de ne pas être utilisé à l'intérieur de la charge utile, vous pouvez définir
NewLine
et l'utilisationReadLine
.Malheureusement (encore!) le paquet contient les binaires de données byte, non ASCII, et, par conséquent, toutes les valeurs de 0x0 à 0xFF sont valides. Merci pour vos suggestions.
OriginalL'auteur mtrw