Få svar tillbaka av ingående FIFO

Här diskuteras programmering och utveckling
Användarvisningsbild
dmz
Inlägg: 3292
Blev medlem: 29 jul 2008, 19:42
OS: Arch Linux

Få svar tillbaka av ingående FIFO

Inlägg av dmz »

Jag har ett program som pratar med ett annat med hjälp av named pipes (fifo).
Det blir en lite halvtråkig konversation då jag aldrig får några svar dock;
jag vet inte om mina kommandon godtas eller inte, och jag kan heller inte få
någon utdata tillbaka.

Så jag funderar på hur man kan lösa detta?
Applikationen som jag talar med är mplayer, och om jag t.ex skickar kommandot
get_file_name via fifon till mplayer så får jag tillbaka filnamnet i
mplayers fönster - hur kan man få det att skickas någon annanstans?
Jag kör mplayer som en daemon, så jag kan ju aldrig se någon output.

ii har t.ex löst det hela med att ha två pipes; en för input och en för output.
ǁ A: Because it obfuscates the reading.
ǁ Q: Why is top posting so bad?
Användarvisningsbild
Konservburk
Inlägg: 5919
Blev medlem: 07 apr 2007, 22:28

Re: Få svar tillbaka av ingående FIFO

Inlägg av Konservburk »

Två pipes är väl en bra idé, eller? Det kan även röra sig om helt vanliga pipes, det behöver ju inte nödvändigtvis vara fifos.

Det går förstås också att kommunicera åt båda hållen över en enda fifo, men det kräver att alla inblandade är helt överrens om exakt när något ska skickas åt det ena respektive det andra hållet. Därmed inte sagt att det ens går att komma överrens om något sådant med just mplayer utan att gå in och pilla på källkoden. Det vet jag inget om.
Användarvisningsbild
dmz
Inlägg: 3292
Blev medlem: 29 jul 2008, 19:42
OS: Arch Linux

Re: Få svar tillbaka av ingående FIFO

Inlägg av dmz »

Min huvudbry är hur jag skall få mplayers output att ta sig till den andra
fifon. Jag insåg dock att detta problem var lättare löst ändå;

Kod: Markera allt

mplayer -quiet -identify -slave -input file=fifo > log
Så är det bara att parse'a utdatan som hamnar i loggen.
Man skulle nog kunna skicka vidare utdatan till en annan pipe också,
jag vet inte vad som blir bäst, än.
ǁ A: Because it obfuscates the reading.
ǁ Q: Why is top posting so bad?
Användarvisningsbild
Konservburk
Inlägg: 5919
Blev medlem: 07 apr 2007, 22:28

Re: Få svar tillbaka av ingående FIFO

Inlägg av Konservburk »

Typ så här borde funka:

Kod: Markera allt

mplayer -quiet -idle -slave <>fifoA >fifoB
Användarvisningsbild
dmz
Inlägg: 3292
Blev medlem: 29 jul 2008, 19:42
OS: Arch Linux

Re: Få svar tillbaka av ingående FIFO

Inlägg av dmz »

fifo_r = read from
fifo_w = write to

Jag fick aldrig din lösning att fungera; troligen på grund av att mplayer
behöver få sin fifo_w utpekad för sig med -slave och -input file.

Anledningen till att jag inte lyckades så bra med två pipes var antagligen
för att jag försökte ha fler än en process att använda dem samtidigt.
Så både lösningen med logfil och två fifos fungerar klockrent.

Jag behöver inte ha fler än en process som läser ifrån fifon, men skulle
gärna vilja kunna skriva till fifo_w från flera ställen samtidigt.
Anledningen är att jag vill kunna styra olika instanser av mplayer
samtidigt.

Jag tar för givet att jag lär skapa en fifo_w för varje instans av mplayer
jag skapar, eller finns det någon bättre lösning?
ǁ A: Because it obfuscates the reading.
ǁ Q: Why is top posting so bad?
Användarvisningsbild
Konservburk
Inlägg: 5919
Blev medlem: 07 apr 2007, 22:28

Re: Få svar tillbaka av ingående FIFO

Inlägg av Konservburk »

dmz skrev:Jag fick aldrig din lösning att fungera; troligen på grund av att mplayer
behöver få sin fifo_w utpekad för sig med -slave och -input file.
Det gick bra när jag testade. Såg du att jag körde med -idle och att du då behöver öppna en fil i efterhand med loadfile? Jag körde följande i tre olika terminaler:

Kod: Markera allt

mplayer -quiet -idle -slave <>fifoA >fifoB

Kod: Markera allt

cat fifoB

Kod: Markera allt

echo "loadfile /path/to/file" >fifoA
dmz skrev:Jag tar för givet att jag lär skapa en fifo_w för varje instans av mplayer
jag skapar, eller finns det någon bättre lösning?
Det beror ju helt på vad du menar med bättre? Du kan inte låta två olika mplayer läsa från samma fifo eftersom bara den ena kan ta emot det som skickas. Vilken det blir är helt slumpmässigt och beror bara på vilken av dem som lyckas läsa först från fifon.

Som jag nämnde tidigare så kan du i princip använda vanliga pipes istället för fifos så slipper du fundera över vad du ska döpa alla olika fifos till.
Användarvisningsbild
dmz
Inlägg: 3292
Blev medlem: 29 jul 2008, 19:42
OS: Arch Linux

Re: Få svar tillbaka av ingående FIFO

Inlägg av dmz »

Konservburk skrev: Det gick bra när jag testade.
Det gjorde det här också när jag följde instruktionerna.
Konservburk skrev: Du kan inte låta två olika mplayer läsa från samma fifo eftersom
bara den ena kan ta emot det som skickas. Vilken det blir är helt
slumpmässigt och beror bara på vilken av dem som lyckas läsa först från
fifon.
Precis. :)
Konservburk skrev: Som jag nämnde tidigare så kan du i princip använda vanliga pipes istället
för fifos så slipper du fundera över vad du ska döpa alla olika fifos till.
Du får gärna visa hur det skulle gå till med vanliga pipes. Rent spontant
så känns det rätt omständigt.

Angående namngivning så lär något sådant här fungera;

Kod: Markera allt

#!/usr/bin/perl
use strict;
my $spawnPlayer = shift or undef;
if($spawnPlayer) {
  require POSIX;
  POSIX::mkfifo("app.@{[time]}.fifo", 0666);
}
Och fifon kommer då alltid att ha ett unikt namn för varje process.
Edit: Något som är än bättre är kanske att helt enkelt använda
processens PID. När processen avslutas så tas aktuell fifo bort.
ǁ A: Because it obfuscates the reading.
ǁ Q: Why is top posting so bad?
Användarvisningsbild
Substrata
Inlägg: 71
Blev medlem: 13 apr 2010, 11:01
OS: Arch Linux
Utgåva: Vet inte/ingen utgåva passar

Re: Få svar tillbaka av ingående FIFO

Inlägg av Substrata »

dmz skrev:Jag behöver inte ha fler än en process som läser ifrån fifon, men skulle
gärna vilja kunna skriva till fifo_w från flera ställen samtidigt.
Anledningen är att jag vill kunna styra olika instanser av mplayer
samtidigt.

Jag tar för givet att jag lär skapa en fifo_w för varje instans av mplayer
jag skapar, eller finns det någon bättre lösning?
Process A serialiserar mplayer med omvärlden.
Process B C D ... öppnar socket till A.

Behöver du flera spelare i A kan du göra ett API (list, tell id ...) för länkarna till B C D ... Du kan använda select(2) i A för att koordinera pipes till spelarna och sockets till omvärlden.

Fast du kanske har instanser av mplayer fördelade i ett nätverk?
Användarvisningsbild
Konservburk
Inlägg: 5919
Blev medlem: 07 apr 2007, 22:28

Re: Få svar tillbaka av ingående FIFO

Inlägg av Konservburk »

dmz skrev:Du får gärna visa hur det skulle gå till med vanliga pipes. Rent spontant
så känns det rätt omständigt.
Typ så här:

Kod: Markera allt

hantera_indatan | mplayer -quiet -idle -slave | hantera_utdatan
Eller kombinera med 1 fifo för att enkelt kunna hantera både indatan och utdatan från samma process:

Kod: Markera allt

hantera_indatan_och_utdatan <fifo | mplayer -quiet -idle -slave >fifo
Men egentligen är väl ett C-program en bra idé här eftersom det ger betydligt större kontroll över hur det hela hanteras. Då kan du dessutom med fördel göra som Substrata föreslår. Jag tänker mig något i stil med:

Kod: Markera allt

#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>

#define MPLAYER "/usr/bin/mplayer"

void forka_loss_mplayer_som_en_daemon(int in[2])
{
	int ut[2];

	if (pipe(in) || pipe(ut))
	{
		exit(EXIT_FAILURE);
	}
	switch(fork())
	{
	case 0:
		if (
			dup2(in[0], STDIN_FILENO) != -1 &&
			dup2(ut[1], STDOUT_FILENO) != -1 &&
			dup2(ut[1], STDERR_FILENO) != -1 &&
			close(in[0]) != -1 &&
			close(in[1]) != -1 &&
			close(ut[0]) != -1 &&
			close(ut[1]) != -1 &&
			chdir("/") != -1 &&
			setsid() != -1 &&
			!fork())
		{
			char * const argp[] = {
				"mplayer", "-quiet", "-idle", "-slave",
				(char *) NULL
			};
			char * const envp[] = {
				"HOME=/",
				(char *) NULL
			};

			umask(0);
			execve(MPLAYER, argp, envp);
		}
	case -1:
		exit(EXIT_FAILURE);
	}
	if (close(in[0]) == -1 || close(ut[1]) == -1)
	{
		exit(EXIT_FAILURE);
	}
	*in = *ut;
	wait(NULL);
}

int main(int argc, char *argv[])
{
	int fd[2];

	forka_loss_mplayer_som_en_daemon(fd);
	ta_hand_om_indatan_och_utdatan(fd);

	exit(EXIT_SUCCESS);
}
Jag har utelämnat funktionen ta_hand_om_indatan_och_utdatan. Den går ju att skriva direkt i C eller så går det att helt enkelt lämna över problemet till något annat program:

Kod: Markera allt

void ta_hand_om_indatan_och_utdatan(int fd[2])
{
	execl("/path/to/annat_program_som_tar_hand_om_indatan_och_utdatan", (char *) NULL);
	exit(EXIT_FAILURE);
}
Ett väldigt enkelt sånt där annat program skulle då kunna se ut så här:

Kod: Markera allt

#!/bin/sh
cat <&5 & cat >&4
Det skyfflar då bara vidare allt som kommer på stdin till pipe:en som går till mplayer och skyfflar på samma sätt bara vidare att som kommer på pipe:en från mplayer direkt till stdout.
Användarvisningsbild
dmz
Inlägg: 3292
Blev medlem: 29 jul 2008, 19:42
OS: Arch Linux

Re: Få svar tillbaka av ingående FIFO

Inlägg av dmz »

Heh, vad underbart. Snyggt jobbat allesammans.
Nu är jag tyvärr inte flytande på C men jag har kod som fungerar i Perl och
det är inga konstigheter att översätta.
Tack för hjälpen!
ǁ A: Because it obfuscates the reading.
ǁ Q: Why is top posting so bad?
Skriv svar

Återgå till "Programmering och webbdesign"