Named Pipe Problem



  • Hallo!

    Ich habe eine c#-Applikation, die eine NamedPipe erzeugt. Dabei soll diese Applikation einen String über die Pipe schreiben können.

    using (pipeServer = new NamedPipeServerStream(PipeName, PipeDirection.Out))
                    {
                        Console.WriteLine("NamedPipeCreated");
                        pipeServer.WaitForConnection();
                        Console.WriteLine("Client connected");
                        try
                        {
                            using (StreamWriter sw = new StreamWriter(pipeServer))
                            {
                                sw.AutoFlush = true;
                                string st = "Hello\0";
                                streamEncoding = new ASCIIEncoding();
                                byte[] output = streamEncoding.GetBytes(st);
                                sw.Write(st);
                            }
                        }
                        catch (IOException e)
                        {
                            Console.WriteLine("ERROR: {0}", e.Message);
                        }
    
                    }
    
    .
    .
    .
    

    Eine c++ - Applikation soll sich mit der NamedPipe verbinden und Daten empfangen können.

    Im Konstruktor ist folgendes definiert:

    pipe = CreateFile(
    		"\\\\.\\pipe\\my_pipe",
    		GENERIC_READ, // only need read access
    		FILE_SHARE_READ | FILE_SHARE_WRITE,
    		NULL,
    		OPEN_EXISTING,
    		FILE_ATTRIBUTE_NORMAL,
    		NULL
    	);
    .
    .
    .
    

    In einer Methode rufe ich das auf:

    result = ReadFile(
    		pipe,
    		buffer, // the data from the pipe will be put here
    		127 * sizeof(wchar_t), // number of bytes allocated
    		&numBytesRead, // this will store number of bytes actually read
    		NULL // not using overlapped IO
    	);
    

    Beide Applikationen verbinden sich mit der Pipe, aber leider werden keine Daten von der C++ Applikation empfangen! Was mache ich falsch? 😕

    Über Hilfe wäre ich sehr dankbar!



  • Nach wenig Recherche und Testen glaub ich, dass das Problem daran liegen könnte, dass wchar_t im unicode Format ist, du aber über die C# Applikation den Text im ascii Format sendest.

    streamEncoding = new ASCIIEncoding();
    byte[] output = streamEncoding.GetBytes(st);
    

    Eine Lösung wäre wchar_t in char zu ändern, danach sollte es gehen, vorausgesetzt es bestehen keine anderen Fehler. Ich würde aber dazu raten, der write Funktion ein char array mitzugeben, dann hast du dieses Problem nicht mehr.

    Test Code:

    static void Main(string[] args)
            {
                NamedPipeServerStream server = new NamedPipeServerStream("my_pipe", PipeDirection.InOut);
                Console.WriteLine("Wait for client to connect");
                server.WaitForConnection();
                Console.WriteLine("Client connected....");
                Console.WriteLine("Sending data....");
    
                using (StreamWriter writer = new StreamWriter(server))
                {
                    writer.AutoFlush = true;
                    char[] data = ("*** Hello Pipe World ***").ToArray<char>();
                    writer.Write(data, 0, data.Length);
                }
    
                Console.WriteLine("Data was sent....");
                Console.ReadLine();
            }
    

    Hier habe ich mich von :
    http://avid-insight.co.uk/joomla/component/k2/item/589-introduction-to-win32-named-pipes-cpp
    bedient.

    int _tmain(int argc, _TCHAR* argv[])
    {
    	wcout << "Connecting to pipe..." << endl;
    
    	// Open the named pipe
    	// Most of these parameters aren't very relevant for pipes.
    	HANDLE pipe = CreateFile(
    		L"\\\\.\\pipe\\my_pipe",
    		GENERIC_READ, // only need red access
     		FILE_SHARE_READ | FILE_SHARE_WRITE,
    		NULL,
    		OPEN_EXISTING,
    		FILE_ATTRIBUTE_NORMAL,
    		NULL
    	);
    
    	if (pipe == INVALID_HANDLE_VALUE) {
    		wcout << "Failed to connect to pipe." << endl;
    		// look up error code here using GetLastError()
    		system("pause");
    		return 1;
    	}
    
    	wcout << "Reading data from pipe..." << endl;
    
    	// The read operation will block until there is data to read
    	char buffer[128];
    	DWORD numBytesRead = 0;
    	BOOL result = ReadFile(
    		pipe,
    		buffer, // the data from the pipe will be put here
    		127 * sizeof(wchar_t), // number of bytes allocated
    		&numBytesRead, // this will store number of bytes actually read
    		NULL // not using overlapped IO
    	);
    
    	if (result) {
    		buffer[numBytesRead] = '\0'; // null terminate the string
    		wcout << "Number of bytes read: " << numBytesRead << endl;
    		wcout << "Message: " << buffer << endl;
    	} else {
    		wcout << "Failed to read data from the pipe." << endl;
    	}
    
    	// Close our pipe handle
    	CloseHandle(pipe);
    
    	wcout << "Done." << endl;
    
    	system("pause");
    	return 0;
    }
    

    Grüsse
    Aero



  • Erst einmal, danke für deine Mühe!

    "Nach wenig Recherche und Testen glaub ich, dass das Problem daran liegen könnte, dass wchar_t im unicode Format ist, du aber über die C# Applikation den Text im ascii Format sendest."

    Das was Du ansprichst, habe ich mir schon gedacht! Wollte aber eine Bestätigung haben!

    Werde das mal morgen antesten, und werde meine Erfahrung hier erläutern!

    Nochmals vielen Dank!

    Grüße 🙂



  • Ich habe jetzt mal zwei Konsolenapplikationen erstellt ( C# und c++)

    Die c# Sharp Applikation sendet an die C++ Applikation. Es funktioniert also!

    Es lag an dem

    streamEncoding = new ASCIIEncoding();
    byte[] output = streamEncoding.GetBytes(st);
    

    😡

    Viellen Dank nochmals 🙂



  • Nichts zu Danken.
    Freut mich, dass ich behilflich sein konnte. 🙂



  • Hallo!

    Die Daten werden mit Hilfe eines Stream-Writer Objekt geschrieben!

    using (StreamWriter writer = new StreamWriter(server))
                {
                    writer.AutoFlush = true;
                    char[] data = ("*** Hello Pipe World ***").ToArray<char>();
                    writer.Write(data, 0, data.Length);
                }
    

    Wie könnte ich es anstellen, dass die Pipe geöffnet bleibt und ich Daten zu einem beliebigen Zeitpunkt senden kann. Nicht in einem Rutsch!

    Ich dachte mir, dass eine while-Schleife weiter helfen könnte!
    Zum Beispiel:

    Die Pipe bleibt geöffnet ....

    ....
    NamedPipeServerStream server = new NamedPipeServerStream("my_pipe", PipeDirection.InOut);
    
                server.WaitForConnection();
    .
    .
    .
    
    isactivate=true;
    
    using (StreamWriter writer = new StreamWriter(server))
                {
                    writer.AutoFlush = true;
                    char[] data = ("*** Hello Pipe World ***").ToArray<char>();
    
                    while(isactivate){
                    writer.Write(data, 0, data.Length);}
                }
    

    Der Code sollte in einem eigenem Thread laufen. Wäre der Ansatz OK?
    Oder würde er ständig durch die While - Schleife Daten schreiben in die Pipe!

    Könnte Jemand einen Tipp geben?



  • Ich enter mal diesen Thread, weil ich ein ähnliches Problem habe. Ich versuche ebenfalls die Pipe offenzuhalten und kriege es nicht hin (Gleiche Konstruktion: C# Server und C++ MFC/Win32 Client) Ich kann auf dem Server erst lesen, wenn der Client die Pipe schliesst. Wieso ist das so bzw wie kann man den Kanal ständig offenhalten? Ich kriege nämlich ein Problem, wenn der Client schon wieder irgendwas fragt und der Server noch keine neue Pipe geöffnet hat.



  • @HelloWorld(): dein Problem ist der using-Block. Nach Verlassen des using-Blocks wird beim StreamWriter Dispose() aufgerufen und dadurch auch das Dispose() auf der Pipe ausgeführt.

    Vielleicht funktioniert folgendes: Du könntest den StreamWriter einmalig instanzieren und benutzt diese eine Instanz um über die Pipe zu kommunizieren. Und am Ende, wenn du die Kommunikation beenden willst, rufst du von Hand ein Close() auf.



  • PuppetMaster2k schrieb:

    @HelloWorld(): dein Problem ist der using-Block. Nach Verlassen des using-Blocks wird beim StreamWriter Dispose() aufgerufen und dadurch auch das Dispose() auf der Pipe ausgeführt.

    Vielleicht funktioniert folgendes: Du könntest den StreamWriter einmalig instanzieren und benutzt diese eine Instanz um über die Pipe zu kommunizieren. Und am Ende, wenn du die Kommunikation beenden willst, rufst du von Hand ein Close() auf.

    Der StreamWriter ist in dem Beispiel nicht notwendig, es wäre auch so möglich gewessen.

    static void Main(string[] args)
            {
                NamedPipeServerStream server = new NamedPipeServerStream("my_pipe", PipeDirection.InOut);
    
                Console.WriteLine("Wait for client to connect");
                server.WaitForConnection();
                Console.WriteLine("Client connected....");
    
                Console.WriteLine("Sending data....");
                byte[] data = Encoding.ASCII.GetBytes("*** Hello Pipe World ***");
                server.Write(data, 0, data.Length);
                server.Write(data, 0, data.Length);
    
                Console.ReadKey();
    
                server.Dispose();
            }
    

    Es muss noch hinzugefügt werden, dass bei dem Beispiel auf C# und C++ Seite Synchron gearbeitet wird. Es wird auf C++ Seite nur einmal auf eine Nachricht gewartet, danach wird die Verbindung geschlossen.

    while(true)
      {
    	  wcout << "Reading data from pipe..." << endl;
    
    		// The read operation will block until there is data to read 
    	  char buffer[128]; 
    	  DWORD numBytesRead = 0; 
    	  BOOL result = ReadFile( 
    		  pipe, 
    		  buffer, // the data from the pipe will be put here 
    		  127 * sizeof(wchar_t), // number of bytes allocated 
    		  &numBytesRead, // this will store number of bytes actually read 
    		  NULL // not using overlapped IO 
    		); 
    
    	  if (result) { 
    		  buffer[numBytesRead] = '\0'; // null terminate the string 
    		  wcout << "Number of bytes read: " << numBytesRead << endl; 
    		  wcout << "Message: " << buffer << endl; 
    		}	else { 
    			wcout << "Failed to read data from the pipe." << endl;
    			break;
    		}
    	}
    

Anmelden zum Antworten