I. 시스템 자원 효율적 사용, Non-Blocking I/O
가. Non-Blocking I/O의 개념
- 소켓 관련 시스템 콜에 대해 네트워크 응답 지연 시 응용 프로그램 Block 방지 I/O 메커니즘
나. 소켓 프로그래밍에서의 Non-Blocking I/O 사용 배경
- 대규모 클라이언트-서버 환경에서, 클라이언트별 쓰레드 생성, 클라이언트 별 read 함수 호출 시 Context Switching 비용 다수 발생하므로 자원의 효율적 사용 위해 Non-Blocking I/O 필요
- 시스템 함수 호출 후 종료 필요 없으며, 버퍼에 데이터 존재 시 Copy, 없으면 넘어가게 되는 방식 → Non-Blocking I/O
II. Non-Blocking I/O 메커니즘
가. Non-Blocking I/O 절차도
- 소켓이 Non-Blocking으로 지정되면 I/O 처리 완료 시까지 대기하지 않고 에러(EWOULD BLOCK) 반환
나. Non-Blocking I/O 절차 설명
# | 수행 절차 | 설명 |
---|---|---|
① | system call / EWOULDBLOCK | – 소켓에 datagram 존재 여부 확인 – datagram 없으면 에러 신호 리턴 |
② | polling (①번 반복) | – 네트워크 소켓에 datagram 존재 여부 지속 확인 (Busy Waiting) |
네트워크 소켓으로 datagram 수신 시 | ||
③ | copy datagram | – 네트워크 소켓의 datagram을 어플리케이션 버퍼로 복사 |
④ | return data | – recvfrom은 성공적으로 리턴, 이후 어플리케이션 데이터 처리 |
- 리눅스 기반 sleep 없는 polling(loop) 시 CPU 100% 점유 문제 발생하므로 해결 필요
III. Non-Blocking I/O 모델 소켓 프로그램 코드
char str[BUF_SIZE] = {0,}; //받을 버퍼 unsigned int strLen = 0; //받고 싶은 데이터의 길이 unsigned int length = 0; //지금까지 받은 데이터의 길이 unsigned int recvLen = 0; //이번에 받은 데이터의 길이 … while(TRUE){ if (recvLen = recv (sock, str+length, strLen, 0) < 0) { //recvfrom 호출하여 결과값 받음. 0보다 작으면 받을 수 있는 데이터가 없음 if (WSAGetLastError() == WSAEWOULDBLOCK){ //WOULDBLOCK이라면 대기시킨다. Sleep( 2000 ); /* Sleep for 2 milliseconds */ }else{ printf(“No data Error.\n”); break; } }else { length += recvLen; if(length >= strLen) break; //다 받았으면 중지 } } |
IV. Non-Blocking I/O의 문제점 및 해결 방안
문제점 | 해결 방안 |
---|---|
– datagram 미 존재 시 polling은 자원 낭비 – 일부 시스템에서 CPU 100% 점유문제 발생 | – I/O 이벤트 통지 모델 – 데이터 수신 시 통지 수행 – 동기식 및 비동기식 모델 |