반응형

http://kldp.org/node/97425

TCP/IP read(), write() timeout 설정

안녕하세요

TCP/IP 소켓 기반으로 간단한 전문을 날리는 함수를 만들었는데요
처음에 read나 write시에 전송이 한번에 이루어지지 않았을때를 대비해서 반복문을 넣으라는
말을 듣고
int recvMSG(int sock, void *buf, int bufLen)
{
int len = 0;
while((len = read(sock, buf, bufLen)) >= 0){
bufLen -= len;
buf += len;
printf("len

d]\n",len);
        if(!bufLen){
            return 0;
        }
    }
    close(sock);
    return -1;
}
이렇게 반복이 되게 만들었어요
 
그런데 문제는 read나 write가 무한정 대기를 막기위해 Timeout을 설정하라는 명령을 듣고
alarm()을써서 막기위해 수정을 했습니다.
==================================
alarm()사용설정
==================================
struct sigaction sigact, oldact;
    sigact.sa_handler = sig_handler;
    sigemptyset(&sigact.sa_mask);
    sigact.sa_flags = 0;
    sigact.sa_flags |= SA_INTERRUPT;
    // 바로 이부분이 SIGNAL 을 받았을때 
    // Interrupt 가 발생하도록 설정하는 부분이다.  
 
    if(sigaction(SIGALRM, &sigact, &oldact) < 0)
    {
        perror("sigaction error : ");
        exit(0);
    }
=========================================
alarm()사용
=========================================
alarm(5);
if (recvMSG(server_sockfd, buf, 80) <= 0)
    {
        printf("test\n");
        if(errno == EINTR)
        {
            printf("signal Interrupt\n");
            return 1;
        }
        perror("read error : ");
        close(server_sockfd);
        exit(0);
    }
====================================================
"위의 구현을 하는데 있어서 핵심은 SIGALRM 에 대해서 interrupt 가 프로세스로 전달되게 하는 부분이다. 또한 read, write 등의 함수가 Interrupt 를 받아서 리턴되었을경우를 처리하기 위한 코드가 추가된다. 이들 함수는 Interrupt 를 받고 리턴되었을경우 errno 값을 EINTR 로 설정함으로 errno 값을 한번만 검사해주면 문제 없이 처리 가능하다."
 
제가 찾은 자료에는 위의 글이 써있었구 또한 read를 대기만 하고 있다면 문제 없이 돌아갑니다.
그러나 문제는 만약 저 read()상태에서 서버가 Ctrl+C를 눌러서 접속을 비정상적으로 종료를 한다면..
실험을 해보니까 
read 반복 되는 함수에서 계속 전송 0리턴 전송 0리턴으로 무한 루프를 돌고 있더라구요
그다음 믿었던 Timeout은 울리지 않습니다. ㅠ
 
다됐다라고 오늘 반나절을 투자한부분이 날라갔어요 ㅠㅠ
이걸 어케 해결해야할지 모르겠네요
도움좀 부탁드려요~ㅠ
 
PS.참고로 UDP가 아니라 TCP로 전송하니까 블록단위 입니다.

read, write의 timeout을

read, write의 timeout을 처리하기 위해서는 select나 poll을 쓰세요.
아니면 asynchronous I/O 를 하시던지

timeout처리를 저렇게 sig_alrm 으로도 처리를 하는군요...처음 알았지만, 그닥 좋은 방법이 아닌거 같네요.
multi-thread를 써서 서버를 만들 때도 저렇게 한다면 시그널은 쓰레드 마다 각각 관리되는게 아니라서
당근 문제가 엄청 많아 질 것이고..

암튼 select나 poll 을 쓰세요.

read의 반환값이 0인

read의 반환값이 0인 경우에도 반복을 중단해야 합니다. 접속이 끊어진 것이니까요.

흠...

좀 안전하게 select같은것을 이용하시고 넌블락 모드로 돌리시면
대부분의 모드에서 잘 작동할것입니다. 이때 주의 하실점은

1. 리턴값을 가지고 판단
2. 그리고 에러번호도 판단의 기준이됨.

이것뿐입니다.

반응형
Posted by 공간사랑
,