socket connect 함수의 처리시간의 조정 방법은 없을 까요 ?

shpark05의 이미지

connect 함수 사용시 , 상대측 서버의 응답이 없을 경우에
이를 빨리 감지하여 접속을 단절 하고 싶습니다.

1-2초 정도 시간만 주려고 합니다만, 특별한 방법이 없을까 궁금합니다.

소켓설정에서 linger 는 사용중입니다.

약 10초정도 텀이 생기는것 같습니다.

서지훈의 이미지

man setsockopt
여기서 SO_RCVTIMEO 이부분을 보시면은 원하는 대답이 될듯 하네요.

<어떠한 역경에도 굴하징 낳는 '하양 지훈'>

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

bw001730의 이미지

저도 맨날 여기서 질문만 올리는데
모처럼 아는거 나와서 답변을 적어봅니다.
혹시나 틀린거 있으면 답변주시길..

제가 회사에서 만든것인데요
아니..만들었다기 보다는 스티븐스 아저씨책에서 약간 수정한거
아니.....거의그대로 가져다 -.- 썼어요

connect() 함수에 타이머 걸기가 어렵게 느껴지는 이유는
connect() 함수가 블럭킹되는 함수이기 때문입니다.
이를 해결하기 위해서...
connect() 함수로 연결을 기다리기 전에
소켓을 non-block 모드로 설정한후에
connect() 호출합니다. 그러면 connect()가 즉시 리턴하거든요, 연결이 되든 안되든...
그후 select()를 호출하면 됩니다.
non-block 소켓이 연결되거나, 타임아웃이 되면 select() 함수가 리턴합니다.
select() 함수의 리턴값을 보고, 연결되었는지 타임아웃인지를 확인할수 있습니다.

그니깐 순서가..
1. 소켓을 non-block 으로 설정
2. connect() 호출--- 즉시 리턴
3. select()로 타임아웃을 기다림
4. 소켓의 non-block 을 해제

머 이런순으로 되겠죠

책보면 다나오는 것이지만... 혹시나 고수님들의 딴지를 기대하며
제가 작성한 소스를 올려봅니다.

님이 궁금해하시는 소스는 connect_nonb() 부분일겁니다.

 int tcp_connect_timeo(const char *hostname, const char *service,int nsec)
 {
     struct addrinfo hints, *res, *ressave;
     int  sock,n;

     bzero(&hints, sizeof(struct addrinfo));
     hints.ai_family = AF_UNSPEC;
     hints.ai_socktype = SOCK_STREAM;

     if( (n=getaddrinfo(hostname,service,&hints,&res)) != 0)
         return -1;
     ressave = res;
     do
     {   
         struct  sockaddr_in *ts;
         sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
         if(sock < 0)
             continue;

         ts = (struct sockaddr_in *) res->ai_addr;

         if(connect_nonb(sock, (struct sockaddr *)res->ai_addr, res->ai_addrlen,nsec) == 0)
             break;
         close(sock);
     }while( (res=res->ai_next) !=NULL);
     if( res == NULL)
         return -1;
     freeaddrinfo(ressave);
     return sock;
 }


int connect_nonb(int sockfd, const struct sockaddr *saptr, int salen, int nsec)
{
    int             flags, n, error;
    socklen_t       len;
    fd_set          rset, wset;
    struct timeval  tval;

    flags = fcntl(sockfd, F_GETFL, 0);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

    error = 0;
    if ( (n = connect(sockfd, (struct sockaddr *) saptr, salen)) < 0)
        if (errno != EINPROGRESS)
            return(-1);

    /* Do whatever we want while the connect is taking place. */

    if (n == 0)
        goto done;  /* connect completed immediately */

    FD_ZERO(&rset);
    FD_SET(sockfd, &rset);
    wset = rset;
    tval.tv_sec = nsec;
    tval.tv_usec = 0;

    if ( (n = select(sockfd+1, &rset, &wset, NULL,
                     nsec ? &tval : NULL)) == 0) {
        close(sockfd);      /* timeout */
        errno = ETIMEDOUT;
        return(-1);
    }

    if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
        len = sizeof(error);
        if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
            return(-1);         /* Solaris pending error */
    } else
        err_quit("select error: sockfd not set");

done:
    fcntl(sockfd, F_SETFL, flags);  /* restore file status flags */
    if (error) {
        close(sockfd);      /* just in case */
        errno = error;
        return(-1);
    }
    return(0);
}
mahapunch의 이미지

정말 가려운데 손이 안닿는 곳을
아주 시원하게 긁어 주는 글이었습니다.
감사해요~

better tommrow than yesterday - cs. shin.

better tommrow than yesterday - cs. shin.

jk3546의 이미지

올려주신 소스 애용 중 입니다. ^^

제가 클라이언트 측이고, 서버에 접속하는데, 끊어졌다고 판단하면 1초당 한번씩 재접 시도 합니다.

근데 처음에는 usec(timeout 시간)을 5000 마이크로 sec 정도 주었었는데, 테스트를 위해서 네트워크

케이블 플러그를 강제로 뺀 상태에서도 가끔 연결되었다고 인지하곤 합니다.

로그 찍어보니 wset, rset 값이 변하더라구요.

시간을 500,000 마이크로 sec 정도 주니 안정화 되기에 충분한 시간이라서 그런지

케이블 뺀 상태에서 연결완료로 인지하진 않았습니다. 하지만 10분에 한건 정도는 발생하는 듯 하네요.

시간을 0.5초에서 더 주어야 할까요??? 이정도면 블라킹 처리할때와 크게 다르지 않겠네요.

뭐가 문제인지...

Necromancer의 이미지

SIGALRM으로 튕겨내는건 어떤가요? alarm() 쓰면 됩니다.

스레드 안쓴다면 가장 간단한 방법이죠.

Written By the Black Knight of Destruction

yielding의 이미지

bw001730 wrote:

제가 회사에서 만든것인데요
아니..만들었다기 보다는 스티븐스 아저씨책에서 약간 수정한거
아니.....거의그대로 가져다 -.- 썼어요

:D

Life rushes on, we are distracted

jinyeong의 이미지

bw001730님의 답변과 흑기사님의 답변이 connection timeout을 주는 방법입니다.

이는 아마도 unp에도 나와 있을테고,

socket faq를 보셔도 두가지 답변이 함께 기술되어 있습니다.

alarm을 쓰실 수 있는 경우라면 그게 간단한 해결책이 되겠지요.

I thought what I'd do was,
I'd pretend I was one of those deaf-mutes.. or should I?

nthroot의 이미지

alarm(5);
connect(...);
alarm(0);

알람을 5초로 걸고 5초안에 alarm(0)을 통해서 해제를 못하게 되면
connect() 함수 블럭 상태에서 자동으로 알람핸들러 함수가 호출되게 됩니다.
connect()는 인터럽트 되게 되고 알람핸들러에서 적당한 처리를 해주시거나
그냥 두시면 됩니다.

정상적으로 connect()에서 연결이 되면 alarm(0)으로 해제가 됩니다.

유닉스 관련 서적에서 시스템콜 alarm 을 보시면 예제들이 있을거에요.

------식은이 처------
길이 끝나는 저기엔 아무 것도 없어요. 희망이고 나발이고 아무 것도 없어.

shpark05의 이미지

감사드립니다. 글을 늦게 확인했습니다 ^^;

:)

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.