Socket 프로세스 처리 중단된 시스템 호출 및 Accept 함수 반환 EINTR 오류 처리

우리는 영원히 막힐 수 있는 시스템 호출 (함수 호출) 을 설명하기 위해 느린 시스템 호출을 사용합니다. 예를 들어 accept,read 등입니다.영원히 막힌 시스템 호출은 호출이 영원히 돌아올 수 없을 수도 있다는 것을 가리키며, 대부분의 네트워크 지원 함수는 이런 종류에 속한다.예를 들어 고객이 서버에 연결되지 않으면 서버가accept에 대한 호출에 대한 보증이 없습니다.유사하게, 만약 고객이 서버에 반사를 요구하는 텍스트를 한 줄도 보내지 않았다면, 서버가read에 대한 호출은 영원히 돌아오지 않을 것이다.다른 느린 시스템 호출의 예는 파이프와 단말기에 대한 읽기와 쓰기이다.예외 중 하나는 디스크 IO인데, 그는 일반적으로 호출자로 돌아간다.프로세스가 막히고 느린 시스템이 호출될 때 신호를 포착하고, 신호 처리 프로그램이 돌아올 때 시스템 호출이 EINTR 오류를 되돌릴 수 있습니다.일부 커널은 중단된 시스템 호출을 자동으로 재개합니다.이식을 편리하게 하기 위해서, 우리가 신호를 포획하는 프로그램을 작성할 때, (대부분의 동시 발송 서버가 SIGCHLD를 포획할 때), 우리는 느린 시스템 호출을 EINTR로 되돌릴 준비를 해야 한다.
중단된 accept를 처리하기 위해서, 우리는 accept의 호출에 대해 최선을 다했고, 다른 느린 시스템 호출 함수도 이 사고방식에 따라 처리할 수 있다.
첫 번째 방법:continue로 for의 다음 순환에 들어가 중단된 시스템 호출을 재개합니다.
for( ; ; ) 
{
    clilen = sizeof(cliaddr);
    if((connfd = accept(listenfd, (SA *)&cliaddr, &clilen)) < 0) {
        if(errno == EINTR) 
            continue;
        else 
            err_sys("accept error");
    }
}

또는 goto로 같은 기능을 실현하고 중단된 시스템 호출을 다시 시작합니다.
Again:
for( ; ; ) 
{
    clilen = sizeof(cliaddr);
    if((connfd = accept(listenfd, (SA *)&cliaddr, &clilen)) < 0) {
        if(errno == EINTR) 
            goto Again;
        else 
            err_sys("accept error");
    }
}

또한 다음과 같이 설명합니다.
느린 시스템 호출에 적용되는 기본 규칙은 느린 시스템 호출에 막힌 프로세스가 어떤 신호를 포착하여 해당하는 신호 처리 함수를 반환할 때 이 시스템 호출은 EINTR 오류를 반환할 수 있다.일부 시스템 코어는 일부 중단된 시스템 호출을 자동으로 재개합니다.이 점은 주의해야 한다.
이 코드에서 우리가 하는 일은 중단된 시스템 호출을 스스로 재개하는 것입니다. 이것은accept 및read,write,select,open 같은 함수에 적합하지만, 우리가 스스로 재개할 수 없는 함수가 있습니다:connect.만약 이 함수가 INTER로 되돌아온다면, 우리는 더 이상 그를 호출할 수 없습니다. 그렇지 않으면 오류가 되돌아옵니다.connet이 포착된 신호에 의해 중단되고 자동으로 다시 시작되지 않을 때, 연결이 끝날 때까지 select를 호출해야 합니다.
마지막으로 accept를 처리하여 EINTR 오류를 반환하는 TCP 서버의 최종 버전을 작성할 때 몇 가지 문제에 주의해야 한다.
>> > fork 하위 프로세스에서 SIGCHLD 신호를 캡처해야 합니다(SIGCHLD 신호는 하위 프로세스가 끝날 때 커널로 보내는 신호입니다).
>>> 신호를 포착할 때 중단된 시스템 호출을 처리해야 합니다
>> > SIGCHLD의 신호 처리 함수(sig_chld)는 정확하게 작성해야 하며waitpid 함수를 사용하여 경직 프로세스를 죽여야 합니다.
다음은 "accept 함수를 처리하여 EINTR 오류가 발생한 TCP 서버 프로그램의 최종 버전으로 되돌려줍니다."
#include <unp.h>

int
main(int argc, char **argv)
{
    int listenfd, connfd;
    pid_t child_pid;
    socklen_t clilen;
    struct sockaddr_in cliaddr, servaddr;
    void sig_chld(int);
    
    listenfd = Socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);
    
    Bind(listenfd, (SA *)&servaddr, sizeof(servaddr));
    listen(listenfd, LISTENQ);
    Signal(SIGCHLD, sig_chld);
    
    for( ; ; ) {
        clilen = sizeof(cliaddr);
        if( (connfd = accept(listenfd, (SA *)&cliaddr, &clilen)) < 0 ) {
            if(errno == EINTR) 
                continue;
            else 
                err_sys("accept error");
        }
        if( (child_pid = Fork()) == 0 ) {
            Close(listenfd);
            str_cli(connfd);
            exit(0);
        }
        Close(connfd);
    }
}

요즘 책을 읽느라 바빠서 블로그를 쓰고 문제를 푸는 시간이 적네요~~

좋은 웹페이지 즐겨찾기