반응형
http://kldp.org/node/97425
TCP/IP read(), write() timeout 설정
글쓴이: anaud2 작성 일시: 목, 2008/08/28 - 7:24오후
안녕하세요
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. 그리고 에러번호도 판단의 기준이됨.
이것뿐입니다.