Comment Asynchrone De Lecture/Écriture D'Un Tube Nommé En C#
J'ai un formulaire Windows qui héberge une coutume de Contrôle de l'Utilisateur. Ce Contrôle Utilisateur déclenche un processus séparé (un .exe) qui crée et initialise une NamedPipeServerStream. Une fois le processus initialise le NamedPipeServerStream, le Contrôle de l'Utilisateur se connecte à elle comme un NamedPipeClientStream.
Tout cela fonctionne très bien.
Sur l'écran de Windows j'ai ensuite un bouton "Check For Updates". Lorsque ce bouton est pressé, la NamedPipeClientStream envoie un message au serveur, dans lequel le serveur qui répond à une MessageBox en disant: "j'ai été dit de vérifier les mises à jour". Donc je peux dire ce client > serveur de communication fonctionne bien.
Voici le problème. Le serveur est alors censé envoyer un message vers le client en lui disant que c'est maintenant la vérification de mises à jour (pour le Contrôle de l'Utilisateur peut mettre à jour son statut après verying sa commande a été reçue par le serveur). Mais chaque fois que cela arrive, tout se bloque.
Maintenant, je vais supposer que c'est parce que j'essaie à la fois de lire ET d'écrire sur le canal Nommé en même temps?
Ci-dessous quelques extraits de code à partir à la fois le Serveur et le Client. (Ces deux extraits de courir sous la forme de plusieurs threads dans leurs processus respectifs de manière à ne pas bloquer l'INTERFACE utilisateur)
GUpdater (Le Serveur De Canal Nommé):
private void WaitForClientCommands()
{
//Wait for a connection from a Named Pipe Client (The GUpControl)
pipeStream.WaitForConnection();
pipeConnected = true;
//Create a StreamWriter/StreamReader so we can write/read to the Named Pipe
pipeStreamWriter = new StreamWriter(pipeStream) { AutoFlush = true };
pipeStreamReader = new StreamReader(pipeStream);
//Now that we have a connection, start reading in messages and processing them
while (true)
{
//Skip this time if we are currently writing to the pipe
if(isWritingToPipe) continue;
var message = pipeStreamReader.ReadLine();
if (message == null)
{
//We don't want to hog up all the CPU time, so if no message was reaceived this time, wait for half a second
Thread.Sleep(500);
continue;
}
switch(message)
{
case "CheckForUpdates":
//MessageBox.Show("Told to check for updates");
SendMessageToClient("Checking For Updates, Woot!");
break;
case "DownloadUpdate":
MessageBox.Show("Told to download update");
break;
case "ApplyUpdate":
MessageBox.Show("Told to apply update");
break;
}
}
}
GUpControl (Le Client De Canal Nommé):
private void WaitForServerCommands()
{
if(!pipeConnected) return;
//Now that we have a connection, start reading in messages and processing them
while (true)
{
//Skip this time if we are currently writing to the pipe
if (isWritingToPipe) continue;
//Attempt to read a line from the pipe
var message = pipeStreamReader.ReadLine();
if (message == null)
{
//We don't want to hog up all the CPU time, so if no message was reaceived this time, wait for half a second
Thread.Sleep(500);
continue;
}
MessageBox.Show("I got a message from the server!!\r\n" + message);
}
}
L'extrait de code suivant est la méthode qui est responsable de la rédaction pour le Client/Serveur de chaque composant. (La seule différence est dans le nom, c'est à dire SendMessageToClient
et SendMessageToServer
)
private void SendMessageToServer(string message)
{
if(pipeConnected)
{
isWritingToPipe = true;
pipeStreamWriter.WriteLine(message);
isWritingToPipe = false;
}
}
La isWritingToPipe
variable est un simple booléen qui est vrai lorsque le processus tente d'écrire le canal Nommé. C'était ma première tentative de résoudre le problème.
Toute aide est très appréciée!
- tout plein des exemples de code source?
Vous devez vous connecter pour publier un commentaire.
System.IO.Pipes.PipeStream
a une méthodeWaitForPipeDrain()
qui est la bonne manière de gérer la coordination entre le client et le serveur lors de l'échange de messages.La TransmissionMode pour le tuyau peut également avoir une incidence choses: êtes-vous à l'aide de mode Octet ou un Message de mode? Je ne suis pas sûr de savoir comment bien enveloppant le flux dans un StreamReader joue avec le tuyau de mode message sémantique, par exemple. Voir cette SORTE de réponse pour en savoir plus sur le message mode.
lorsque vous envoyez un signal au serveur pour vérifier les mises à jour puis le faire en classe BackgroundWorker
La solution à ce problème s'est avéré être une question de repenser la conception du logiciel.
Au lieu d'avoir un UserControl qui parle à une application séparée à chaque étape du processus de mise à Jour, le contrôle UserControl s'occupe de tout lui-même et puis, enfin, quand il en a besoin pour appliquer la mise à jour (qui consiste à écraser les fichiers de l'application, d'où la nécessité d'un autre processus, en premier lieu), il utilise simplement le Processus.Début("...") ainsi que quelques ligne de commande arguments pour appeler un autre processus pour terminer le travail.
Une solution beaucoup plus simple que d'essayer de faire de la Communication Inter-Processus pour cette tâche.
Encore, il aurait été agréable de trouver pourquoi ma communication Bi-Directionnelle n'étais pas de travail.