[C++][socket][mac os] SIGPIPE 시그널

2024. 5. 8. 13:48네트워크 프로그래밍

1. 개요

Mac OS 환경에서  C++언어로 서버-클라이언트 구조로 게임 데이터를 서버에서 클라이언트에게 소켓통신으로 루프문을 돌면서 전송중이었다. 이때 고의 클라이언트 연결을 끊어보았다. (Ctrl + C), 이경우에 서버 프로세스도 종료되었다.

 

2. 원래 의도

나의 의도는 클라이언트에서 연결을 끊더라도 서버는 연결을 끊기지 않는 것이었고, 클라이언트의 연결의 끊겼을때 recv를 통해 연결끊김을 핸들링 하고 있으니 괜찮다고 생각했다. 하지만 클라이언트 연결이 끊길때마다 서버 연결이 끊겨서 이유를 찾아보았다.

LLDB등으로 디버깅을 하고, 프린트를 이곳저곳 찍어보아도 왜 끊기는지 이유를 모르겠었다..

 

3. 서버 연결이 끊긴 이유

 

위 사진처럼 echo $?로 마지막으로 종료된 프로세스 상태를 확인해보았는데 정상종료(0)이 아닌 141이 나왔다. 상당히 의심스러워서 코파일럿으로 찾아보니 아래와같은 답변을 주었다.

 

#Question
echo $? 의 결과가 141이면 무슨뜻이야?

#Copilot
echo $? 명령은 이전에 실행된 명령의 종료 상태를 출력합니다. 종료 상태는 프로그램이 성공적으로 종료되었는지, 
아니면 오류로 인해 종료되었는지를 나타냅니다.

종료 상태 141은 프로그램이 SIGPIPE 시그널로 종료되었음을 나타냅니다. 
SIGPIPE는 프로세스가 파이프를 통해 데이터를 쓰려고 시도했지만, 
읽는 쪽의 프로세스가 이미 종료되었을 때 발생합니다. 이는 종종 파이프라인의 일부 명령이 실패했을 때 발생합니다. 
예를 들어, command1 | command2에서 command1이 아직 데이터를 쓰고 있는데 
command2가 종료되면 이런 상황이 발생할 수 있습니다.

 

어쨋든 SIGPIPE시그널 때문에 서버프로세스가 종료된거였다. 

 

4. 해결방법

어쨋든 게임중 클라이언트가 끊겼을때 서버가 종료되면 안되기에 SIGPIPE를 핸들링 해주는 방법으로 해결해주었다.

SIGPIPE 발생시 서버측에서 연결이 끊겼다고 출력을 해주었다. SIGPIPE가 발생하는 지점에서 프로세스가 끊기지 않게만 해주면

그 이후에 recv함수를 통해서 연결이 끊기면 해당 클라이언트 정보를 저장하고 있던 배열에서 fd값을 삭제해주기 때문에 문제가 발생하지 않았다.

 

int main(int ac, char **av)
{
    std::signal(SIGINT, signalHandler); // Ctrl + C
    std::signal(SIGTERM, signalHandler); // kill
    std::signal(SIGPIPE, signalHandler); //SIGPIPE
    //....
}

void signalHandler(int signum) {
    if (signum == SIGINT)
        std::cout << "SIGINT: Interrupt signal received" << std::endl;
    else if (signum == SIGTERM)
        std::cout << "SIGTERM: Termination signal received" << std::endl;
    else if (signum == SIGPIPE)
    {
        std::cout << "SIGPIPE: Broken pipe signal received" << std::endl;
        atom_stop = true;
        cleanThread();
        return ; //연결 끊지 않고 스레드 메모리만 해제
    }
    else
        std::cout << "Others: Signal " << signum << " received" << std::endl;
    atom_stop = true;
    std::cout << "signalHandler atom_stop = true" << std::endl;
    cleanMemory();
    exit(signum);
}