2016-07-03 2 views
1

현재 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

답변

0

논리가 올바르지 않은 것 같습니다.

if(iFIFO != 0) 

if(iFIFO == -1) 

open 이후 반환 -1 오류에 있어야합니다. 그렇지 않으면 유효한 파일 설명자를 리턴합니다.

0

open() 새로 생성 된 파일 설명자를 반환합니다. 새 프로세스가 이미 파일 설명자 0을 가지고 있다는 간단한 이유 때문에 0을 반환 할 수 없습니다. 표준 입력이됩니다.

반환 값 3은 open()에서 예상되는 결과입니다.이 경우 표준 입력, 출력 및 오류 후에 사용 가능한 다음 파일 설명자가 될 수 있기 때문입니다. open()이 파일 설명자를 열 수 없으면 -1을 반환합니다.

하지만 그 외에

는, 코드가 다른 버그의 무리가 : 프로세스 ID가 (가능하다) 만 3 자리로 발생하는 경우

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

// ... 

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

를,이 파이프에 3 바이트를 기록합니다 .

프로세스 ID가 5 자리 숫자 (더 많은 가능) 인 경우 5 바이트 길이의 sPID 버퍼에 쓰여진 총 6 바이트에 대해 5 바이트와 '\ 0'바이트를 씁니다 배열을 오버런하여 정의되지 않은 동작이 발생합니다.

실제 결과는, 물론입니다 정의되지 않은, 그러나 일반적인 C++ 구현은 스택의 다음 변수, 무엇이든의 첫 번째 바이트 건드리지 종료됩니다 :

int iFIFO; 

는 것입니다 당신의 파일 기술자. 운이 좋지 않고 새 프로세스가 5 자리 프로세스 ID를 얻었고 little-endian 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'을 배치해야합니다 (물론 읽기 버퍼가 충분히 큰지 확인해야합니다).