命名管道文件描述符
Named pipe file descriptor
目前我正在为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,' '};
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',' '};
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;
}
}
终端输出
输出open()
返回新创建的文件描述符。它不能返回0,原因很简单,因为新进程已经有一个文件描述符0。这将是标准输入。
在本例中,返回值3是open()
的预期结果,因为它将是标准输入、输出和错误之后的下一个可用文件描述符。如果open()
不能打开文件描述符,它将返回-1。
但除此之外,你的代码还有一堆其他的bug:
sprintf(sPID, "%d",myPID);
// ...
write(iFIFO, sPID, strlen(sPID));
如果您的进程ID恰好只有3位数字长(这是可能的),这将向管道写入三个字节。
如果您的进程ID恰好是五位数字长(甚至更有可能),这将写入5个字节加上' '字节,总共写入6个字节到5字节长的sPID
缓冲区,超出数组并导致未定义的行为。
的实际结果当然是未定义的,但典型的c++实现最终会删除堆栈上的下一个变量的第一个字节,即:
int iFIFO;
是你的文件描述符。所以,如果你的运气用完了,你的新进程得到一个五位数的进程id,这是一个小端序的c++实现,没有填充,那么iFIFO
的低阶字节被设置为0,如果代码编译时没有任何优化,iFIFO
文件描述符被设置为0。Hillarity。
此外,在管道的另一边:
char sPID[5] = {0,1,2,3,' '};
// ...
read(iFIFO, sPID, strlen(sPID));
因为SPID
的第一个字节总是设置为0,这将始终执行read(iFIFO, sPID, 0)
,而不读取任何内容。
:
pid = atoi(sPID);
atoi()
期望一个以' '结尾的字符串。read()
只读取它所读取的内容,它不会' '终止它最终读取的内容。在使用atoi()
之前,您有责任放置' '来终止读输入(当然,要确保读缓冲区足够大)。
你的逻辑似乎不正确。
if(iFIFO != 0)
应该if(iFIFO == -1)
因为open
在错误时返回-1。否则,它返回一个有效的文件描述符。
- 使用VerQueryValue检索应用程序的文件描述
- 如何在C/C++中用FD_set Unix设置套接字文件描述符
- 如何使用管道在父级和子级之间来回传递文件
- I2C 文件描述符上的 I2C 总线可写/可读标志
- GLib-ERROR:为GWakeup创建管道:打开的文件太多
- 许多文件描述符在调用sys_clone时
- AMQP-CPP >处理程序中的错误文件描述符
- 如何使用 WINAPI 和 C++ 提取可执行文件的文件描述?
- 如何在 bash 中使用管道在 c++ 中使用 getenv() 访问文件?
- 正在等待在非阻塞文件描述符上长时间运行ioctl
- 有没有适用于Windows.lib文件的GNU二进制文件描述符(BFD)
- 如何强制文件描述符缓冲我的输出
- 使用 Select 多路复用未命名的管道和其他文件描述符
- read() 上的不同行为取决于写入不可写内存时表示文件、匿名管道或套接字的文件描述符
- 命名管道,选择错误的文件描述符C++
- 如何检查文件指针/描述符/句柄是否关联到同一个文件/管道/终端
- exe 文件中的描述和文件版本
- 无法将管道的写端作为文件描述器传递
- Open()、Close()和Read()应用于Linux管道文件描述符
- 命名管道文件描述符