PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : IPC: Named pipes wieder zumachen und anderes



axeljaeger
26-12-2002, 12:32
Ich arbeite gerade an einem OggVorbisPlayer, dem ich jetzt auch ein KonsolenInterface verpassen möchte,
etwa das ich in der Konsole schreiben kann:

"player -stop" und die Wiedergabe wird gestoppt, ohne das eine weitere Instanz des Players gestartet wird.

Dazu hab ich bei Pronix.de die Möglichkeit gefunden, named pipes zu verwenden. Die Funktion




#include <sys/types.h>
#include <sys/stat.h>

int mkfifo(const char *pfadname, mode_t mode);



soll eine Pipe aufmachen. Jetzt hab ich mir gedacht, bevor das Programm etwas in die Pipe schreibt,
muß es erstmal wissen, ob auch jemand aus der Pipe liest. Ich wollte das so machen, das ich die
Pipe beim Start des Programmes erstelle und hinterher wieder zumache. Ein neuer Prozess muß
dann nur gucken, ob es die Pipe gibt. Dazu brauch ich aber noch zwei Funktionen:

- Herausfinden, ob die Pipe existiert
- Pipe wieder zumachen

Beides steht nicht dabei. Vielleicht könnt ihr helfen, und auch mal sagen, ob das ein gutes Verfahren ist,
was ich mir da ausgedacht habe, oder ob ich es lieber anders machen sollte

anda_skoa
26-12-2002, 17:54
Vielleicht geht das mit einem Unix Domain Socket leichter.

Ich muß zugeben, dass ich mich damit noch nicht so beschäftigt habe, aber ich habe das so verstanden, dass es fast wie ein Inertnetsocket ist, nur dass die Adresse praktisch ein Filename ist.

Du hättest also eine Art Playerdaemon, der den Socket erzeugt und dann dort lesend wartet.

Wenn der PLayerclient nicht dorthin connecten kann, muß er einen daemon starten.

Ciao,
_

axeljaeger
26-12-2002, 19:22
Ja, so in etwa hab ich mir das gedacht, nur das der Daemon eine GUI hat. Kannst du mal etwas Code oder einen Link zu Unix-Domain-Sockets posten? Damit hab ich mich nämlich noch nicht beschäftigt. Vielleicht könnte ich auch was mit DCOP basteln, ich weis nur nicht, ob das geht, da ich kein QT verwende

f0rtex
26-12-2002, 19:33
Hier ein kleiner Unix-Domain-Server und ein dazugehöriger Client. Sollte für den Anfang hilfreich sein. :-)

uclient.c


/***
* uclient.c - Einfacher Client für Unix-Domain-Sockets
*
* Verbindet sich mit dem ./sample-socket Unix Domain Socket,
* kopiert stdin in den Socket und beendet sich dann.
***/

#include <sys/socket.h> /* connect(), bind(), listen(), accept() */
#include <sys/un.h> /* sockaddr_un */
#include <unistd.h> /* unlink() */
#include "sockutil.h"

int main(void)
{
struct sockaddr_un address;
int sock;
size_t addrLength;

if((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
die("socket");

address.sun_family = AF_UNIX;
strcpy(address.sun_path, "./sample-socket");

/***
* Länge der Adresse inklusive Grösse des sun_family Elements
***/
addrLength = sizeof(address.sun_family) + strlen(address.sun_path);

if(connect(sock, (struct sockaddr *) &address, addrLength))
die("connect");

copyData(0, sock);

close(sock);

return 0;
}



userver.c


/***
* userver.c - Einfacher Server für Unix-Domain-Sockets
*
* Wartet auf eine Verbindung am ./sample-socket Unix Domain Socket.
* Ist die Verbindung hergestellt, werden alle Daten von diesem Socket
* nach stdout kopiert, bis die Verbindung vom anderen Ende geschlossen
* wird, dann warten auf neue Verbindung.
***/

#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include "sockutil.h"

int main(void)
{
struct sockaddr_un address;
int sock, conn;
size_t addrLength;

if((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
die("socket");

/***
* Berets vorhandene(n) Socket/Datei entfernen
***/
unlink("./sample-socket");

address.sun_family = AF_UNIX;
strcpy(address.sun_path, "./sample-socket");

/***
* Länge der Adresse inklusive Grösse des sun_family-Elements
***/
addrLength = sizeof(address.sun_family) + strlen(address.sun_path);

if(bind(sock, (struct sockaddr *) &address, addrLength))
die("bind");

if(listen(sock, 5))
die("listen");

while((conn = accept(sock, (struct sockaddr *) &address, &addrLength)) >= 0){
printf("---- Hole Daten ----\n");
copyData(conn, 1);
printf("---- Fertig ----\n");
close(conn);
}

if(conn < 0)
die("accept");

close(sock);
return 0;
}



Unix-Domain-Sockets haben eine einzigartige Fähigkeit: Mit ihnen können Dateideskripotren übergeben werden. Ein Prozess kann dadurch eine Datei öffnen und deren Dateideskriptor an einen anderen - möglicherweise völlig beliebigen -Prozess weitergeben. Die Zugriffsrechte werden nur beim Öffnen der Datei berücksichtigt, so dass der den Dateideskriptor erhaltende Prozess die gleichen Rechte auf die Datei erhält wie der Ursprungsprozess.
Für die Übergabe von Dateideskriptoren sind die Funktionen


#include <sys/socket.h>
int sendmsg(int fd, const struct msghdr * msg, unsigned int flags);
int recvmsg(int fd, const struct msghdr * msg, unsigned int flags);

zuständig.

anda_skoa
28-12-2002, 16:34
Original geschrieben von axeljaeger
Ja, so in etwa hab ich mir das gedacht, nur das der Daemon eine GUI hat.


Nunja, da wäre es eventuell dann sinnvoller, den Daemon ohne GUI zu machen.



Kannst du mal etwas Code oder einen Link zu Unix-Domain-Sockets posten?


Vielen Dank an f0rtex für diesen ausführlichen Beispielcode.
Ich hätte sicher keinen so guten gefunden.

Ciao,
_

axeljaeger
29-12-2002, 12:22
Ja, gut, Daemon macht man normal ohne GUI, aber es macht doch keinen Sinn, die PlayerUI zustarten und dazu noch einen Daemon, der drauf wartet, Nachrichten entgegen zu nehmen. Außerdem muß die GUI ja dann wieder benachrichtigt werden.

Das mit dem Netzwerksocket scheint ja noch den Vorteil zu haben, das der Socket automatisch wieder zugemacht wird, wenn der Server beendet wird, auch wenn er unsachgemäß beendet wird. (Kann schon mal passieren bei meinen Player, nutzt intensiv NV-OpenGL)