Named Pipes sind eine
Methode zur Interprozess-Kommunikation (IPC) auf Windows-Betriebssystemen. Sie
ermöglichen die Übertragung von Daten zwischen Prozessen auf demselben Computer
oder über das Netzwerk. Eine Named Pipe ist ein benanntes, unidirektionales oder
bidirektionales Kommunikationskanal zwischen Prozessen. Ein Prozess (z.B.
Server) erstellt eine Named Pipe und gibt ihr einen Namen. Andere Prozesse (z.B.
Clients) können sich dann mit der Named Pipe verbinden, indem sie ihren Namen
angeben.
Named Pipes sind ähnlich wie anonyme Pipes, die ebenfalls zur
Interprozesskommunikation verwendet werden können. Der Hauptunterschied besteht
darin, dass Named Pipes einen Namen besitzen und von jedem Prozess auf dem
System oder im Netzwerk verwendet werden können, während anonyme Pipes nur
zwischen verwandten Prozessen verwendet werden können.
Named Pipes
unterstützen verschiedene Modi, wie z.B. Byte-Stream-Modus oder Message-Modus,
und verschiedene Übertragungsmodi wie z.B. Blocking-Modus oder
Non-Blocking-Modus. Sie können auch Sicherheitseinstellungen konfigurieren, um
den Zugriff auf die Named Pipe zu steuern.
Auf Windows-Betriebssystemen
können Named Pipes mit der Windows-API erstellt und verwendet werden.
Die
wichtigsten Funktionen sind CreateNamedPipe,
ConnectNamedPipe, CreateFile, ReadFile
und WriteFile.
Zunächst erstellen wir das
Server-Programm, das die Named Pipe erstellt.
Wir verwenden
Multithread-Programmierung, damit sich mehrere Clients anbinden können.
/*
Hier ist ein Beispiel für die
Verwendung von Named Pipes in C++ auf Windows,
das ohne
Cygwin oder MinGW in Microsoft Visual Studio ausgeführt werden kann.
Dieses Programm erstellt eine Named
Pipe mit dem Namen `\\\\.\\pipe\\MyPipe` und
wartet auf
eine Verbindung von einem Client.Wenn ein Client verbunden ist,
sendet das Programm eine Nachricht an den Client und beendet dann die
Verbindung.
Dieses
Programm erstellt eine Named Pipe und wartet auf Verbindungen von Clients.
Wenn ein Client verbunden ist, erstellt das
Programm einen neuen Thread, um die Verbindung zu verarbeiten.
Im
Thread wird eine Nachricht an den Client gesendet und dann die Verbindung
beendet.
Auf diese Weise kann das
Serverprogramm mehrere Clients gleichzeitig bedienen,
indem es für
jeden Client einen neuen Thread erstellt.
Du kannst dieses Programm in Microsoft Visual
Studio kompilieren und ausführen.
Stelle sicher, dass du das Windows
SDK in deinem Projekt eingebunden hast,
damit du auf
die Windows - API - Funktionen zugreifen kannst.
*/
#define NOMINMAX //
due to conflict with max()
#include <windows.h>
#include <iostream>
#include <limits>
void wait()
{
std::cin.clear();
std::cin.ignore((std::numeric_limits<std::streamsize>::max)(), '\n');
std::cin.get();
}
DWORD WINAPI ClientThread(LPVOID
lpParam)
{
HANDLE pipe =
(HANDLE)lpParam;
// Send a message to the client
const char* message = "Hello from the server!";
DWORD
bytesWritten;
BOOL result = WriteFile(
pipe, // pipe handle
message, // message
strlen(message) + 1, // message length
&bytesWritten, //
bytes written
NULL); // not overlapped
if (!result)
{
std::cerr << "WriteFile failed: " << GetLastError() << std::endl;
}
DisconnectNamedPipe(pipe);
CloseHandle(pipe);
return 0;
}
int main()
{
while (true)
{
// Create a named pipe
HANDLE pipe = CreateNamedPipe(
TEXT("\\\\.\\pipe\\MyPipe"), // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
1024, // output buffer size
1024,
// input buffer size
NMPWAIT_USE_DEFAULT_WAIT, // client time-out
NULL); // default security attribute
if (pipe == INVALID_HANDLE_VALUE)
{
std::cerr << "CreateNamedPipe failed: " << GetLastError() << std::endl;
return -1;
}
std::cout << "Waiting for client to connect..." << std::endl;
// Wait for the client to connect
BOOL result = ConnectNamedPipe(pipe, NULL);
if (!result)
{
std::cerr << "ConnectNamedPipe failed: " << GetLastError() << std::endl;
CloseHandle(pipe);
return -1;
}
std::cout << "Client connected." << std::endl;
// Create a thread to handle the client connection
HANDLE thread = CreateThread(
NULL, // default security attributes
0, // default stack size
ClientThread,// thread function name
(LPVOID)pipe,// argument to thread function
0, // use default creation flags
NULL); // returns the thread identifier
if (thread == NULL)
{
std::cerr << "CreateThread failed: " << GetLastError() << std::endl;
DisconnectNamedPipe(pipe);
CloseHandle(pipe);
return -1;
}
}
wait();
return 0;
}
Nun benötigen wir einen oder mehrere Clients, die die Named Pipe aufrufen.
/*
Hier ist ein Beispiel für einen Named Pipe-Client in
C++ auf Windows,
der
sich mit einer Named Pipe verbindet und eine Nachricht vom Server empfängt.
Dieses Programm verbindet sich mit einer Named Pipe
mit dem Namen \\\\.\\pipe\\MyPipe
und liest eine Nachricht vom Server.
Die Funktion CreateFile() wird
verwendet, um eine Verbindung zur Named Pipe herzustellen.
Die Funktion ReadFile() wird
verwendet, um Daten von der Pipe zu lesen.
Du kannst dieses Programm in Microsoft Visual Studio
kompilieren und ausführen.
Stelle sicher, dass du das Windows SDK in deinem
Projekt eingebunden hast,
damit du auf die Windows-API-Funktionen zugreifen
kannst.
*/
#define NOMINMAX // due to conflict with max()
#include <windows.h>
#include <iostream>
#include <limits>
void wait()
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cin.get();
}
int main()
{
// Connect to the named pipe
HANDLE pipe = CreateFile(
TEXT("\\\\.\\pipe\\MyPipe"), // pipe name
GENERIC_READ |
// read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default
attributes
NULL); // no template file
if (pipe == INVALID_HANDLE_VALUE)
{
std::cerr << "CreateFile failed: " << GetLastError() << std::endl;
return -1;
}
std::cout << "Connected to server." << std::endl;
//
Read a message from the server
char buffer[1024];
DWORD bytesRead;
BOOL result = ReadFile(
pipe, // pipe handle
buffer, // buffer to receive reply
sizeof(buffer),// size of buffer
&bytesRead, // number of
bytes read
NULL); // not overlapped
if (!result)
{
std::cerr << "ReadFile failed: " << GetLastError() << std::endl;
}
else
{
std::cout << "Received message from server: " << buffer << std::endl;
}
CloseHandle(pipe);
wait();
return 0;
}