gpt4 book ai didi

c++ - 命名管道文件描述符

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:24:06 25 4
gpt4 key购买 nike

目前我正在为 Linux 操作系统制作 C/C++ 程序。我想使用命名管道在两个程序之间传递 PID(进程 ID)。管道已创建并在目录中可见。

Get PID 程序说文件描述符返回 3,而如果它可以打开管道它应该返回 0。我做错了什么?

获取PID

// Several includes
using namespace std;

int main(int argc, char *argv[]) {
pid_t pid;
int sig = 22;
int succesKill;
int iFIFO;
char sPID[5] = {0,1,2,3,'\0'};
iFIFO = open("IDpipe" , O_RDONLY);
if(iFIFO != 0)
{
cerr << "File descriptor does not return 0, but: " << iFIFO << endl;
return EXIT_FAILURE;
}
read(iFIFO, sPID, strlen(sPID));
cerr << "In sPID now is: " << sPID << endl;
close(iFIFO);
pid = atoi(sPID);
cout << "The PID I will send signals to is: " << pid << "." << endl;
while(1)
{
succesKill = kill(pid, sig);
cout << "Tried to send signal" << endl;
sleep(5);
}
return EXIT_SUCCESS;
}

发送PID

// Several includes
using namespace std;

void catch_function(int signo);

volatile sig_atomic_t iAmountSignals = 0;

int main(void) {
pid_t myPID;
int iFIFO;
char sPID[5] = {'l','e','e','g','\0'};
myPID = getpid();
sprintf(sPID, "%d",myPID);
cout << "My PID is: " << sPID << endl;
iFIFO = open("IDpipe" , O_WRONLY);
if(iFIFO == -1)
{
cerr << "Pipe can't be opened for writing, error: " << errno << endl;
return EXIT_FAILURE;
}
write(iFIFO, sPID, strlen(sPID));
close(iFIFO);
if (signal(22, catch_function) == SIG_ERR) {
cerr << "An error occurred while setting a signal handler." << endl;
return EXIT_FAILURE;
}
cout << "Raising the interactive attention signal." << endl;
if (raise(22) != 0) {
cerr << "Error raising the signal." << endl;
return EXIT_FAILURE;
}
while(1)
{
cout << "iAmountSignals is: " << iAmountSignals << endl;
sleep(1);
}
cout << "Exit." << endl;
return EXIT_SUCCESS;
}

void catch_function(int signo) {
switch(signo) {
case 22:
cout << "Caught a signal 22" << endl;
if(iAmountSignals == 9)
{iAmountSignals = 0;}
else
{++iAmountSignals;}
break;
default:
cerr << "Thats the wrong signal.." << endl;
break;
}
}

终端输出

Output

最佳答案

open() 返回新创建的文件描述符。它不能返回 0,原因很简单,因为新进程已经有一个文件描述符 0。那将是标准输入。

返回值 3 是 open() 的预期结果,在本例中,因为这将是标准输入、输出和错误之后的下一个可用文件描述符。如果 open() 无法打开文件描述符,它将返回 -1。

但除此之外,您的代码还有许多其他错误:

sprintf(sPID, "%d",myPID);

// ...

write(iFIFO, sPID, strlen(sPID));

如果您的进程 ID 恰好只有 3 位数字长(这是可能的),这将向管道写入三个字节。

如果您的进程 ID 恰好是五位数长(更有可能),这将写入 5 个字节加上 '\0' 字节,总共写入六个字节到五个字节长的 sPID 缓冲区,溢出数组并导致未定义的行为。

当然,实际结果是未定义的,但典型的 C++ 实现最终会破坏堆栈中下一个变量的第一个字节,即:

int iFIFO;

这是你的文件描述符。所以,如果你的运气用完并且你的新进程获得了一个五位数的进程 ID,并且这是一个小端 C++ 实现,没有填充,那么 iFIFO 的低位字节被设置到 0,如果代码在没有任何优化的情况下编译,iFIFO 文件描述符将设置为 0。随之而来的是喜怒无常。

此外,在管道的另一边:

char sPID[5] = {0,1,2,3,'\0'};

// ...

read(iFIFO, sPID, strlen(sPID));

因为 SPID 的第一个字节总是设置为 0,所以这将始终执行 read(iFIFO, sPID, 0),而不会读取任何内容。

之后:

pid = atoi(sPID);

atoi() 需要一个以“\0”结尾的字符串。 read() 只读取它读取的任何内容,它不会'\0'-终止它最终读取的任何内容。在使用 atoi() 之前,您有责任放置一个终止读取输入的“\0”(当然,还要确保读取缓冲区足够大)。

关于c++ - 命名管道文件描述符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38170190/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com