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. 그리고 에러번호도 판단의 기준이됨.
이것뿐입니다.
댓글 달기