signal과 socket

hammer의 이미지

시그널 대기하는 sigprocmask를 써서 제가 짜고 있는
프로그램에 적용할려고 하니
에러가 나더군요. (accept부분에서 Interupted System call이라고..) 소켓 연결도 하지 않았는데 말입니다.
짤막한 저의 프로그램을 소스를 보여드리면..

int main()
{
    int i = 0;
    struct sigaction intsig, usrsig;
   .........
   ........

    usrsig.sa_handler = sig_usr;
    sigemptyset(&usrsig.sa_mask);
    usrsig.sa_flags = 0;

    intsig.sa_handler = sig_int;
    sigemptyset(&intsig.sa_mask);
    intsig.sa_flags = 0;

    if (sigaction(SIGINT, &intsig, 0) == -1)
    {
        printf ("signal(SIGALRM) error");
        return -1;
    }    

    if (sigaction(SIGUSR2, &usrsig, 0) == -1)
    {
        printf ("signal(SIGUSR2) error");
        return -1;
    }        
    if ((tcp_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket ");
        exit(-errno);
    }

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(PORT);

    if (bind(tcp_fd, (struct sockaddr *)&server_addr,sizeof(server_addr)) < 0) {
        perror(" bind ");
        exit(-errno);
    }
    if (listen(tcp_fd, 1) < 0) {
        perror("listen ");
        exit(-errno);
    }

    for (;;) {
        conn_fd = accept(tcp_fd, (struct sockaddr *)&server_addr, &addr_size);
        if (conn_fd < 0) {
            perror("accept ");
        }
        server_comm(conn_fd);
        close(conn_fd);
    }

}
void sig_int(int signo)
{
    sigset_t sigset, oldset;
    sigfillset(&sigset);
    
    if (sigprocmask(SIG_BLOCK, &sigset, &oldset) < 0)
    {
        printf("sigprocmask %d error \n", signo);
    }
    fprintf(stderr, "SIGINT !!!!\n");
    sleep(5);
}

void sig_usr(int signo)
{
    sigset_t sigset, oldset;
    sigfillset(&sigset);
    
    if (sigprocmask(SIG_BLOCK, &sigset, &oldset) < 0)
    {
        printf("sigprocmask %d error \n", signo);
    }
    fprintf(stderr, "SIGUSR2 !!!!\n");
    sleep(5);
}

이런식으로 되어있는데요.
시그널을 발생해서 하면 시그널 자체는 실행이 잘되는데
시그널을 마치고 올때 accept()부분에서 에러가 나더군요
왜그럴까요?

그리고 시그널을 대기하는 것처럼 socket연결도 시그널 수행중에 소켓연결을 시그널이 마칠때까지 기다린후 수행을하는 방법과 통신이 되는중에도 발생한 시그널을 대기시켜서 통신이 끝나면 시그널이 대기된것이 수행하는 방법이 있으면 가르쳐 주십시요

etourist의 이미지

안녕하세요.

우선 코드도 건성으로보고 답변을하는 저를 용서하십시오. 8)

문제는 아마 이럴 것입니다.

1. 시그널 S에 대한 핸들러 등록.
2. accept() 에서 블록 중.
3. S 발생!
4. S 핸들링하고 accept()로 반환.
5. accept()는 errno에 EINTR를 설정하고 -1을 반환.

Quote:

EINTR
The system call was interrupted by a signal that was caught before a valid connection arrived.

님께서 올린 코드를 보면, accept()가 반환한 디스크립터가 -1이면 바로 perror()를 호출하게 되어있기때문에, 님께서 지적하신 에러메시지가 출력되는거라 사료됩니다. 그렇다면 그 위에 다음 코드를 추가해보면 어떨가 생각됩니다.

일단 errno.h를 포함하시고.

if (conn_fd <0 && errno == EINTR)
     continue;    /* 계속 기다릴래~ */

그럼. 즐거운 시간되세요~

"꿈이 있는 자는 흔들리지 않는다! "

[url]http://ldk.sarang.net [/url]
"꿈이 있는 자는 흔들리지 않는다! "

hammer의 이미지

말씀하신되로 하닌깐 잘되네요..감사합니다.^^
다른 질문이 몇가지 있는데요.
sigprocmask를 이용해서 시그널이 오는 도중에 다른 시그널이 오면 대기했다가
마치고 나서 다른 시그널이 수행이 되는데요..
이 방법 말고 sa_mask를 이용해서 하는 방법이 있다고 하는데 이건 어떻게 사용해야 하는지 궁금합니다. 그리고 다른 예제들을 보니
sigfillset(&sigset);
if (sigprocmask(SIG_BLOCK, &sigset, &oldset) < 0) {
perror("sigprocmask ");
return;
}
시그널 루틴 끝나기 전에
if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0) {
perror("sigprocmask ");
return;
}
이런식으로 되어 있던데. 꼭 해줘야 하는지 알고싶습니다.
제 생각엔 예전 mask값으로 셋팅해주는거 가튼데..

그리고 이것처럼 socket통신중에 시그널이 오면 대기했다가 통신이 마치면 시그널이 수행되도록 할 수 있습니까?
그리고 시그널 도중에 accept에서 통신 연결이 되면 대기했다가 시그널이 끝나면
통신이 바로 수행할 수 있습니까?
만약되면..답변 부탁드리겠습니다.
그럼 수고하십시요.

unixguy의 이미지

좀 다른 이야기입니다만

유닉스 시스템 프로그래밍할 때는 항상 이 시그날을 염두에 두어야 하는 데, 어떤 시스템콜(open(), read(), write() ...) 을 사용하든 지 특별한 경우가 아니면 처음에 코딩할 때 부터 'if ( (콜==실패) && errno == EINTR)) 이면 다시' 부분을 추가해놓는 습관을 들이는 것이 좋다고 생각합니다.

안 하고 시스템콜을 수백군 데 해서 나뒀다가 나중에 10초마다의 타이머가 필요하다고 알람을 설치하는 등의 요구사항이 생기면 골치아파 질 것 같지요?

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.