命名管道文件描述符

Named pipe file descriptor

本文关键字:描述 管道文件      更新时间:2023-10-16

目前我正在为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。否则,它返回一个有效的文件描述符。