我目前有分叉两个进程的代码。第一个进程读取 http 流广播并将数据推送到管道(用 打开pipe()
),以便第二个进程使用 OSS 读取、解码并输出到声卡。
我一直在尝试调试解码部分(单独的问题),并且遇到一种情况,当我打印出来时,管道的文件描述符为 0。据我所知,这意味着标准输入。这是管道的一个已知问题吗?它可能会意外打开标准文件描述符之一?如果是这样,我该如何解决它?
我的管道/叉子代码如下。还有很多其他代码,我希望它们是无关紧要的。
//this is the "switch channel" loop
while(1)
{
/*create the pipes
*
* httpPipe is for transfer of the stream between the readProcess and the playProcess
*
* playPPipe is for transfer of commands from the main process to the playProcess
*
* readPPipe is for transfer of commands from the main process to the readProcess
*
*/
if(pipe(httpPipe) == -1)
{
cout << "ERROR:: Error creating httpPipe: " << endl;
}
if(pipe(PlayPPipe) == -1)
{
cout << "ERROR:: Error creating PlayPPipe: " << endl;
}
if(pipe(ReadPPipe) == -1)
{
cout << "ERROR:: Error creating ReadPPipe: " << endl;
}
cout << "httpPipe:" << httpPipe[0] << ":" << httpPipe[1] << endl;
cout << "PlayPPipe:" << PlayPPipe[0] << ":" << PlayPPipe[1] << endl;
cout << "ReadPPipe:" << ReadPPipe[0] << ":" << ReadPPipe[1] << endl;
pid = fork();
if(pid == 0)
{
/* we are in the readProcess
* this process uses libcurl to read the icestream from the url
* passed to it in urlList. It then writes this data to writeHttpPipe.
* this continues until the "q" command is sent to the process via
* readPPipe/readReadPPipe. when this happens the curl Callback function
* returns 0, and the process closes all fds/pipes it has access to and cleans
* up curl and exits.
*/
rc = 0;
close(httpPipe[0]);
writeHttpPipe = httpPipe[1];
close(ReadPPipe[1]);
readReadPPipe = ReadPPipe[0];
rc = readProcess(urlList.at(playListNum));
if(rc > 0)
{
cout << "ERROR:: has occured in reading stream: " << urlList.at(playListNum) << endl;
close(writeHttpPipe);
close(readReadPPipe);
exit(16);
}
}else if(pid > 0)
{
pid = fork();
if(pid ==0)
{
/* we are in the PlayProcess
* the playProcess initialises libmpg123 and the OSS sound subsystem.
* It then reads from httpPipe[0]/readHttpPipe until it recieves a "q" command
* via PlayPPipe[0]/readPlayPPipe. at which point it closes all fd's and cleans
* up libmpg123 handles and exits.
*/
close(httpPipe[1]);
sleep(1);
close(PlayPPipe[1]);
readPlayPPipe = PlayPPipe[0];
playProcess();
exit(0);
}else if(pid > 0)
{
/* This is the main process
* this process reads from stdin for commands.
* if these are valid commands it processes this command and
* sends the relevant commands to the readProccess and the PlayProcess via
* the PlayPPipe[1]/writePlayPPipe and ReadPPipe[1]/writeReadPPipe.
* It then does suitable clean up.
*/
string command;
//close ends of pipe that we don't use.
close(ReadPPipe[0]);
close(PlayPPipe[0]);
close(httpPipe[0]);
close(httpPipe[1]);
//assign write ends of pipes to easier variables
writeReadPPipe = ReadPPipe[1];
writePlayPPipe = PlayPPipe[1];
rc = 0;
//wait for input
while(1)
{
cin >> command;
cout << command << endl;
rc = 0;
/* Next channel command. this sends a q command to
* readProccess and playProcess to tell them to cleanup and exit().
* then it breaks out of the loop, increments the playListNum and
* we start all over again. The two processes get forked, this time with a new channel
* and we wait for input.
*/
if(command == "n")
{
rc = sendCommand("q");
if(rc != 0)
{
cout << "ERROR: failed to send command: " << command << ":" << endl;
}
break;
}
/* Quit program command.
* This sends a command to the two proceesses to cleanup and exit() and then exits.
*
*/
if(command == "q")
{
rc = sendCommand("q");
if(rc != 0)
{
cout << "ERROR: failed to send command: " << command << ":" << endl;
}
exit(0);
}
}
}else
{
cout << "ERROR:: some thing happened with the fork to playProcess..." << endl;
}
}else
{
cout << "ERROR:: some thing happened with the fork to readProcess..." << endl;
}
//clean up the pipes otherwise we get junk in them.
close(writePlayPPipe);
close(writeReadPPipe);
delete json;
//Parse JSON got from the above url into the list of urls so we can use it
JsonConfig *json = new JsonConfig(parms->GetParameter("URL"));
json->GetConfigJson();
json->ParseJson();
json->GetUrls(urlList);
cout << "####---->UrlListLength: " << urlList.size() << endl;
//increment which url in the list we are going to be playing next.
playListNum++;
//if the playlist is greater than or equal to the urlist size then we are back at the start of the list
if(playListNum >= (int)urlList.size())
{
playListNum = 0;
}
}
这个循环是为了让我可以浏览广播电台列表。当按下“n”时,它会向两个子进程发送一个命令,将它们彻底关闭,然后关闭所有管道并循环回来,再次打开所有管道并再次分叉这两个进程。
第一次经过循环时,似乎可行,但第二次时,我得到以下输出。
URL: 192.168.0.5:9000/playlist
GetConfigJsonurl: 192.168.0.5:9000/playlist
httpPipe:3:4
PlayPPipe:5:6
ReadPPipe:7:8
GetConfigJsonurl: 192.168.0.5:9000/playlist
####---->UrlListLength: 2
httpPipe:0:4
PlayPPipe:7:8
ReadPPipe:9:10
所以基本上我想知道如何阻止管道打开 std 文件描述符。
答案1
新的文件描述符始终占据尚未使用的最低整数。
$猫>测试.c main(){退出(打开(“/dev/null”,0));} ^D $抄送测试.c $./a. 输出;回声$? 3 $./a.out <&-;回声$? 0 $./a.out >&-;回声$? 1
系统不关心“标准文件描述符”或类似的东西。如果文件描述符 0 被关闭,则将在 0 处分配一个新的文件描述符。
您的程序或启动方式中是否有任何地方可能导致close(0)
?
答案2
strace 可以让您了解可执行文件对文件描述符执行的操作:
strace -f -e trace=file,desc,ipc -o /tmp/strace.txt /path/to/exe arg1 arg2...