NamedPipes - Nachricht von Client an Server wird nicht im Server angezeigt/kommt nicht an(?)

  • C#

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von ClonkAndre.

    NamedPipes - Nachricht von Client an Server wird nicht im Server angezeigt/kommt nicht an(?)

    Hi,

    ich habe eine Konsolenanwendung, und ein Script (DLL) das als Mod für ein Spiel dient.
    Nun würde ich gerne zwischen Konsole und Script Daten austauschen.
    Ich habe mich für NamedPipes entschieden.

    Wenn ich nun einen string von Client zu Server schicke, dann wird in meiner Konsole nichts angezeigt das etwas empfangen wurde.
    Wenn ich jedoch von meinem Server eine Nachricht zum Client schicke, dann wird meine Nachricht die ich vom Client zum Server geschickt habe auf einmal doch in der Konsole angezeigt.

    Ich bin neu in der Entwicklung mit NamedPipes also könnte ich eure Ratschläge gut gebrauchen.

    Hier mal mein momentaner Code vom Server:
    Spoiler anzeigen

    C#-Quellcode

    1. namespace PipeServerTest {
    2. class Program {
    3. private static NamedPipeServerStream server;
    4. private static StreamReader sr;
    5. private static StreamWriter sw;
    6. static void Main(string[] args)
    7. {
    8. try
    9. {
    10. server = new NamedPipeServerStream("testPipe123", PipeDirection.InOut, 1);
    11. while (true)
    12. {
    13. server.WaitForConnection();
    14. sr = new StreamReader(server);
    15. sw = new StreamWriter(server);
    16. // Ich habe auch schon versucht diesen Block auszukommentieren
    17. string input = Console.ReadLine();
    18. if (!string.IsNullOrWhiteSpace(input))
    19. {
    20. sw.WriteLine(input);
    21. sw.Flush();
    22. }
    23. //
    24. if (sr.Peek() > 0) {
    25. string msg = sr.ReadLine();
    26. Console.WriteLine("Message: " + msg);
    27. }
    28. server.Disconnect();
    29. }
    30. }
    31. catch (Exception ex)
    32. {
    33. Console.WriteLine("Error: " + ex.Message);
    34. }
    35. }
    36. }
    37. }



    Und hier der aktuelle Code vom Client:
    Spoiler anzeigen

    C#-Quellcode

    1. private bool Pipe_IsRunning;
    2. private bool Pipe_IsConnected;
    3. private string Pipe_Name;
    4. private NamedPipeClientStream Pipe_Client;
    5. private StreamReader Pipe_sr;
    6. private StreamWriter Pipe_sw;
    7. #region Methods
    8. private bool StartPipe(string pipeName)
    9. {
    10. if (!Pipe_IsRunning) {
    11. Pipe_Name = pipeName;
    12. Pipe_IsRunning = true;
    13. Pipe_Process();
    14. return true;
    15. }
    16. return false;
    17. }
    18. private bool StopPipe()
    19. {
    20. try {
    21. if (Pipe_IsRunning) {
    22. Pipe_IsRunning = false;
    23. if (Pipe_sr != null) {
    24. Pipe_sr.Dispose();
    25. Pipe_sr = null;
    26. }
    27. if (Pipe_sw != null) {
    28. Pipe_sw.Dispose();
    29. Pipe_sw = null;
    30. }
    31. return true;
    32. }
    33. return false;
    34. }
    35. catch (Exception ex) {
    36. Game.Console.Print("Pipe stop error. Details: " + ex.Message);
    37. return false;
    38. }
    39. }
    40. private bool WritePipe(string input)
    41. {
    42. try {
    43. if (Pipe_sw != null) {
    44. // Wenn ich "Task.Run" rausnehme, dann friert das Spiel komischerweiße ein, erst wenn ich den server schließe läuft das Spiel normal weiter
    45. Task.Run(() => {
    46. Pipe_sw.WriteLine(input);
    47. Pipe_sw.Flush();
    48. Pipe_Client.WaitForPipeDrain();
    49. });
    50. //
    51. return true;
    52. }
    53. return false;
    54. }
    55. catch (Exception) {
    56. return false;
    57. }
    58. }
    59. #endregion
    60. private void Pipe_Process()
    61. {
    62. Task.Run(() => {
    63. while (Pipe_IsRunning) {
    64. if (Pipe_IsRunning) {
    65. using (NamedPipeClientStream client = new NamedPipeClientStream("localhost", Pipe_Name, PipeDirection.InOut)) {
    66. try {
    67. client.Connect();
    68. Pipe_Client = client;
    69. Pipe_sr = new StreamReader(client);
    70. Pipe_sw = new StreamWriter(client);
    71. if (Pipe_sr.Peek() > 0) {
    72. string msg = Pipe_sr.ReadLine();
    73. Game.DisplayText(msg);
    74. }
    75. }
    76. catch (IOException) {
    77. // ...
    78. break;
    79. }
    80. }
    81. }
    82. }
    83. });
    84. }



    Woran könnte es liegen?


    Falls noch weitere Fragen bestehen stellt diese gerne.
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!
    Welche Logik steckt hinter

    C#-Quellcode

    1. while (Pipe_IsRunning) {
    2. if (Pipe_IsRunning) {

    Der ganze Pipe_Process kommt mir komisch vor. Da wird ja alle x Mikrosekunden nach jeder Servernachricht die Verbindung aufgebaut und wieder getrennt, Dank des using-Blocks. Das ist doch nicht Sinn der Sache, oder?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    VaporiZed schrieb:

    Welche Logik steckt hinter
    C#-Quellcode
    while (Pipe_IsRunning) {
    if (Pipe_IsRunning) {

    Habs vergessen rauszunehmen. :whistling:

    VaporiZed schrieb:

    Das ist doch nicht Sinn der Sache, oder?


    Ne, da hast Du Recht, das ist nicht Sinn der Sache. Ich werde es mal ändern, mal schauen was ich für ein Ergebniss bekomme.
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!
    Ich habe den Code von Server und Client etwas geändert.

    Server sieht nun so aus:
    Spoiler anzeigen

    C#-Quellcode

    1. static void Main(string[] args)
    2. {
    3. try
    4. {
    5. server = new NamedPipeServerStream("testPipe123", PipeDirection.InOut, 1);
    6. server.WaitForConnection();
    7. sr = new StreamReader(server);
    8. sw = new StreamWriter(server);
    9. while (true)
    10. {
    11. string input = Console.ReadLine();
    12. if (!string.IsNullOrWhiteSpace(input)) {
    13. sw.WriteLine(input);
    14. sw.Flush();
    15. }
    16. if (sr.Peek() > 0) {
    17. string msg = sr.ReadLine();
    18. Console.WriteLine("Message: " + msg);
    19. }
    20. }
    21. }
    22. catch (Exception ex)
    23. {
    24. Console.WriteLine("Error: " + ex.Message);
    25. }
    26. }



    Client sieht nun so aus:
    Spoiler anzeigen

    C#-Quellcode

    1. private void Pipe_Process()
    2. {
    3. Task.Run(() => {
    4. Pipe_Client.Connect();
    5. Pipe_sr = new StreamReader(Pipe_Client);
    6. Pipe_sw = new StreamWriter(Pipe_Client);
    7. while (Pipe_IsRunning) {
    8. try {
    9. if (Pipe_sr.Peek() > 0) {
    10. string msg = Pipe_sr.ReadLine();
    11. //PipeDataReceived(msg);
    12. Game.DisplayText(msg, 3500);
    13. }
    14. }
    15. catch (IOException ex) {
    16. Game.Console.Print(ex.Message);
    17. break;
    18. }
    19. }
    20. });
    21. }



    Ich hoffe es ist ein bisschen besser geworden ;)

    Problem mit diesem Code ist jedoch nun: Client und Server können sich jeweils nur noch eine Nachricht gegenseitig schicken, danach können keine Nachrichten mehr versendet werden. (Zumindest vom Server aus nicht weil ich kann dann nichts mehr in der Console eingeben.)
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!
    @ClonkAndre Du kannst doch das Studio zwei Mal öffnen und in jedem einen Teil Deiner Kommunikation laufen lassen.
    Das Debuggen ist da zwar etwas schwierig, aber es ist möglich.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich find's gerade (wohl aufgrund von Unwissenheit) interessant:
    Server

    C#-Quellcode

    1. using System;
    2. using System.IO;
    3. using System.IO.Pipes;
    4. namespace PipeServerTest
    5. {
    6. class Program
    7. {
    8. private static NamedPipeServerStream server;
    9. private static StreamWriter sw;
    10. static void Main(string[] args)
    11. {
    12. try
    13. {
    14. server = new NamedPipeServerStream("testPipe123", PipeDirection.InOut, 1);
    15. server.WaitForConnection();
    16. sw = new StreamWriter(server);
    17. while (true)
    18. {
    19. string input = Console.ReadLine();
    20. if (!string.IsNullOrWhiteSpace(input))
    21. {
    22. sw.WriteLine(input);
    23. sw.Flush();
    24. }
    25. }
    26. }
    27. catch (Exception ex)
    28. {
    29. Console.WriteLine("Error: " + ex.Message);
    30. }
    31. }
    32. }
    33. }

    Client

    C#-Quellcode

    1. using System;
    2. using System.IO;
    3. using System.IO.Pipes;
    4. namespace PipeClientCS
    5. {
    6. class Program
    7. {
    8. private bool Pipe_IsConnected;
    9. private string Pipe_Name;
    10. private NamedPipeClientStream Pipe_Client;
    11. private StreamReader Pipe_sr;
    12. private StreamWriter Pipe_sw;
    13. private void ConnectPipe(string pipeName)
    14. {
    15. if (Pipe_IsConnected) return;
    16. InitializePipe(pipeName);
    17. CommunicateWithPipeServer();
    18. }
    19. private void InitializePipe(string pipeName)
    20. {
    21. Pipe_Name = pipeName;
    22. Pipe_IsConnected = true;
    23. }
    24. private void CommunicateWithPipeServer()
    25. {
    26. Pipe_Client = new NamedPipeClientStream("localhost", Pipe_Name, PipeDirection.InOut);
    27. Pipe_Client.Connect();
    28. Pipe_sr = new StreamReader(Pipe_Client);
    29. Pipe_sw = new StreamWriter(Pipe_Client);
    30. while (Pipe_IsConnected)
    31. {
    32. try
    33. {
    34. while (Pipe_sr.Peek() == -1) ;
    35. string msg = Pipe_sr.ReadLine();
    36. Console.WriteLine("got a message from server: " + msg);
    37. if (Pipe_sr.EndOfStream) Console.WriteLine("Ende der Verbindung");
    38. }
    39. catch (IOException ex)
    40. {
    41. Console.WriteLine(ex.Message);
    42. break;
    43. }
    44. }
    45. }
    46. private void DisconnectPipe()
    47. {
    48. if (!Pipe_IsConnected) return;
    49. Pipe_IsConnected = false;
    50. if (Pipe_sr != null)
    51. {
    52. Pipe_sr.Dispose();
    53. Pipe_sr = null;
    54. }
    55. if (Pipe_sw != null)
    56. {
    57. Pipe_sw.Dispose();
    58. Pipe_sw = null;
    59. }
    60. }
    61. static void Main(string[] args)
    62. {
    63. Program Program = new Program();
    64. Program.ConnectPipe("testPipe123");
    65. Program.DisconnectPipe();
    66. }
    67. }
    68. }

    So kann ich Nachrichten vom Server an den Client schicken. Kommentiere ich aber Z#42 beim Client aus, klappt es nicht mehr. ?(
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Hey,

    warum das Rumgefummel mit StreamReader.Peek()? Man hat einen NamedPipeServerStream, aus dem jeweils ein StreamReader und StreamWriter erzeugt wird. Nutzt man StreamReader.ReadLine(), so blockiert dieser solange, bis auf der anderen Seite StreamWriter.WriteLine() aufgerufen wird. Wichtig ist hier, dass StreamWriter.Flush() genutzt wird. Oder man erzeugt das StreamWrtier-Objekt gleich mit AutoFlush = true.

    Hier mein Beispiel für dieses Problem, welches auch mehr als einen Client handeln kann.

    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.IO;
    4. using System.Net;
    5. using System.Net.Sockets;
    6. using System.IO.Pipes;
    7. using System.Threading.Tasks;
    8. namespace NET5Console2
    9. {
    10. class Program
    11. {
    12. static void Main(string[] args)
    13. {
    14. Task.Run(Connect);
    15. Console.ReadLine();
    16. }
    17. static void Connect()
    18. {
    19. NamedPipeServerStream server = new NamedPipeServerStream("test", PipeDirection.InOut, 50);
    20. server.WaitForConnection();
    21. Task.Run(Connect);
    22. Task.Run(() => HandleConnection(server));
    23. }
    24. static void HandleConnection(NamedPipeServerStream server)
    25. {
    26. StreamReader sR = new StreamReader(server);
    27. StreamWriter sW = new StreamWriter(server) { AutoFlush = true };
    28. Console.WriteLine("New client.");
    29. while (true)
    30. {
    31. try
    32. {
    33. string message = sR.ReadLine();
    34. sW.WriteLine(message);
    35. }
    36. catch
    37. {
    38. Console.WriteLine("Client disconnected");
    39. server.Disconnect();
    40. server.Dispose();
    41. break;
    42. }
    43. }
    44. }
    45. }
    46. }



    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.IO;
    4. using System.Net;
    5. using System.Net.Sockets;
    6. using System.IO.Pipes;
    7. namespace NET5Console3
    8. {
    9. class Program
    10. {
    11. static void Main(string[] args)
    12. {
    13. NamedPipeClientStream client = new NamedPipeClientStream("test");
    14. StreamReader sR;
    15. StreamWriter sW;
    16. try
    17. {
    18. client.Connect();
    19. sR = new StreamReader(client);
    20. sW = new StreamWriter(client) { AutoFlush = true };
    21. }
    22. catch
    23. {
    24. Console.WriteLine("Could not connect.");
    25. Console.ReadLine();
    26. return;
    27. }
    28. while (true)
    29. {
    30. try
    31. {
    32. string input = Console.ReadLine();
    33. if (input == "exit")
    34. {
    35. throw new Exception();
    36. }
    37. sW.WriteLine(input);
    38. Console.WriteLine(sR.ReadLine());
    39. }
    40. catch
    41. {
    42. Console.WriteLine("Communication error.");
    43. client.Close();
    44. client.Dispose();
    45. break;
    46. }
    47. }
    48. }
    49. }
    50. }



    Ein einfacher Echo-Server, der das Gesendete einfach an den Client zurück schickt. Jede Server-Instanz läuft bei mir in einem eigenen Thread, um mehrere Clients handeln zu können.
    Die Unendlichkeit ist weit. Vor allem gegen Ende. ?(
    Manche Menschen sind gar nicht dumm. Sie haben nur Pech beim Denken. 8o
    @SpaceyX
    Vielen Dank für dein Beispiel. Es funktioniert soweit sehr sehr gut.
    Also... lag es wirklich an StreamReader.Peek()? Wenn ich zuerst checke, ob der Peek größer als 0 ist, dann kann ich eine Nachricht an den Server schicken (und der Server sendet diese auch zurück), bei der nächsten Nachricht aber, wird die Nachricht nicht mehr vom Server zurück gesendet und ich kann im Client nichts mehr in die Konsole eingeben.
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!
    Hier habich mich mal mit NamedPipes beschäftigt, im Zusammenhang der Server-Client-Architektur eines primitiven BroadCast Chats: VersuchsChat mit leistungsfähigem Server

    BroadCast bedeutet: eine Nachricht wird an alle verstreut. Antworten werden nicht erwartet.

    BroadCast ist aber nur eine Form der Kommunikation. Eine andere ist Peer to Peer, wo Nachrichten nur zw. 2 Partnern ausgetauscht werden.

    Noch eine Dimension ist Responsibilität, wo Nachrichten eine direkte Antwort erwarten.

    Daher ist deine Problembeschreibung uneindeutig, weil man muss jeweils spezifisch vorgehen.
    Deine Versuche mit StreamReader.Peek() deuten für mich aber darauf hin, dass du iwas mit Responsibilität versuchst.

    Da habe ich auch einen Ansatz für - aber auf einem anderen Blatt.
    Die Beispiele von @SpaceyX haben bei mir wunderbar funktioniert! Danke dafür :).
    Ich habe es zuerst mit 2 Konsolen Anwendungen getestet (Server/Client). Nun benutzte ich es zwischen einer DLL-Datei (welche eine Mod für ein Spiel ist) und einer Windows Forms Anwendung.

    @ErfinderDesRades
    Richtig, Responsibilität war mein vorhaben. Der Client soll zum Server zum Beispiel: get:username senden, der Server Antwortet mit username:NAME (Was Server und Client nun auch erfolgreich tun).
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!