non-block 소켓을 이용한 비동기(asynchronous) 통신에서 질문입니다.
글쓴이: freestyle / 작성시간: 일, 2007/12/16 - 6:05오후
다음과 같은 상황에서 어떤 C/S 모델을 선택하여야 할까요? http://kldp.org/node/88932
이전에 제가 올린 글을 통해 얻은 답변을 바탕으로
'non-block 소켓을 이용한 비동기(asynchronous) 통신'을 하려고 합니다.
인터넷 검색을 통해서 소켓 통신의 다양한 모드에 대해서 공부해 보고
non-block 소켓을 다음과 같이 만든다는 것을 알았습니다.
int flags; flags = Fcntl(sockfd, F_GETFL, 0); Fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
그런데 궁금한 점은 예제들에서 connect할 때만 잠깐 타임아웃을 걸기 위해 사용하고,
정작 소켓 통신 과정에서는 non-block을 해제하고 통신한다는 것입니다.
http://www.pie.pe.kr/cgi-bin/moin.cgi/NonblockingSocket
위 링크의 예제는 connect time-out을 걸기위한 것이긴 하지만,
제가 찾을 수 있는 문서는 다 이런 식이군요.
분명 recv와 같은 block류의 함수에서 바로 에러를 리턴하기 위해서는 그 상황에서
non-block 모드여야 할텐데...
검색된 글을 봐도 확실히 그런 것 같은데요( http://kldp.org/node/69143 의 mach님 답변 )...
계속 헤매고 있습니다.
어린 중생, 밝은 빛은 빛으로 인도해 주세요 orz
Forums:
네, 짐작하신대로
네, 짐작하신대로 recv를 해서 바로 에러나 수신 상태를 확인할려면 여전히 non-block 로 사용해야 합니다.
하지만 다른 예제에서는 block 모드로 사용했는데요. 그렇게 해도 되는 이유는 select 를 이용해서
소켓의 상태에 따라 처리를 해기 때문입니다.
즉, block 이든 아니든 상관없이 select를 통해서 특정 socket에서 read 할 데이터가 있다는 것을 확인 했기 때문에
recv를 하게 되면 무조건 무언가가(접속이 끊기거나 수신이 됐거나) return 이 된다는 것이 보장이 되는거죠.
그렇기 때문에 예제들은 그냥 block으로 되돌리고 select를 사용한 것 같네요.
만약, select 등과 같은 event 모니터링을 별도로 하지 않고 read함수등을 통해 async 하게 recv상태를 확인하고 싶다면
꼭 non-block 소켓을 사용해야겠지요.
...
논-블록킹 모드로 프로그래밍을 한다는 것은 먼저 블록킹의 의미를 명확히 해야합니다.
보통의 의미로, "운영체제(커널)에게 어떤 요청을 하고, 결과를 운영체제가 알려줄때까지 기다린다."라는 것이 블록킹입니다. 이는 다른 쪽에도 통하는데, "데이터베이스 서버에 요청하고, 그 결과를 데이터베이스서버가 알려줄때까지 기다린다."도 같은 얘기입니다.
예를 들어, connect()를 호출하면 보통은 운영체제가 원격지와 연결하고 그 결과를 알려줍니다. 연결하는데, 지연가능한 시간은 1초 이내, 수초 또는 수분이 될 수도 있습니다. 하나의 연결을 위해 이를 수행하는 프로세스는 장시간을 대기(블록킹)할 수 있으며, 그 수행시간을 예측할 수 없고, 특히, 한 프로세스/쓰레드로 다수 개의 연결을 관리하고자 할때는 부적절합니다.
connect()만이 블록킹 모드로 수행된다고 생각하면 안됩니다. read(), write(), accept()도 이렇게 블록킹모드로 수행을 하게 됩니다.(유닉스의 시스템호출은 블록킹/논블록킹으로도 분류된다는...) 그중 connect/accept는 비교적 사용빈도가 낮은 호출이고, read/write는 전자에 비해 무수히 많은 호출이 이뤄지게 됩니다. 따라서, 논블록킹 방식으로 프로그램을 한다는 것은 connect()/accept()부분뿐만 아니라, 다른 부분(read/write)에서 더 필요로 함을 알 수 있습니다.
심지어, 서버가 클라이언트와 통신뿐 아니라, 다른 서버(전형적으로는 데이터베이스서버등)와 연계되어 있는 경우라면, 여기서도 블록되지 않도록 해야 합니다.(mach 자서전의 "서버 어록"중 하나이지요 - 검색하지 마세요. 없어요.)
즉, 통신 프로그램에서 사용한 함수(시스템호출, 라이브러리 호출등) 하나 하나가 절대로 블록되어서는 안된다는 얘기입니다.
심지어 사용자가 만든 유틸리티 함수들도 루프를 가지는 경우 절대적으로 그 수행이 예측되는 응답시간내에 이뤄지도록 만들어야 함을 의미합니다.
read에서 블록킹을 피한다는 것은 궁극적으로 버퍼관리를 사용자 프로그램에서 수행한다는 것을 의미합니다. 그동안 커널의 tcpip프로토콜 스택에서 받아주고 보내주고 했던 부분을 사용자 수준에서 상당 부분 판단 및 처리해야 함을 의미합니다. 좀 까다로운 부분이지요. 그나마 단일 연결에서 이를 처리하는 것은 비교적 단순한 편입니다만, 다중 연결을 가지는 통신 프로그램에서, 버퍼관리를 사용자 수준에서 하는 것은 의외로 까다로운 작업에 해당되기에 이 부분은 예를 찾아보기 어려워서 아마도 connect부분 예제만(상대적으로 매우 단순) 찾아 보실 수 있었을 것입니다. 전체적인 통신에 걸쳐서 논블록킹 관련 얘기를 게시판에 올리기에는 좀 과한 얘기가 되리라고 봅니다.
이러한 부분(read/write 및 외부 서버인터페이스)을 논 블록킹으로 만든 것들은 미들웨어 프로그램에서 찾아보실 수 있을 것입니다. 즉, tcp 레이어와 응용레이어 사이에 존재하는 미들웨어 수준의 프로그램 또는 라이브러리에서 찾아보실 수 있습니다. SSL도 그 한 예가 될 수 있습니다. TCP와 응용사이에서 자신만의 레이어 SSL을 만들어 응용과 tcp단의 통신을 제어하고 있습니다. SSL을 미들웨어로 바라보기에는 좀 아햏햏하고, SSL 소스를 바라보는 것은 별로 재미 없는 일이겠지만, 이 곳에서도 유사한 고민을 찾을 수 있을 것입니다. 그외 메시지 패싱 관련 다수의 미들웨어들이 그러하고 있습니다.
버퍼관리를 사용자로 가져오는 것이 어렵게 느낄때는, 질문자께서 언급하신 제가 했던 답변 http://kldp.org/node/69143 에서 처럼 송/수신 직후에만 블록킹을 해제하여 하는 방식이 단순하여 좋다고 봅니다.
버퍼관리만으로 모든 문제가 풀리지는 않지만, 기본이 됨은 더 말할 여지가 없습니다.
결론적으로, 미들웨어라는 제품을 요구하는 것이 아닌, 특정 응용의 비즈니스 로직이 중요하다면, 특정 통신 프로그램 프레임워크를 추종하는 것보다는 가장 자신있는 것으로 수행하는게 좋다는 생각입니다. 또는 기존에 존재하는 미들웨어를 도입해서 사용해 보는것도 좋은 접근이라고 봅니다. 컴파일러론에서 보듯이, bottom-up 방식만이 좋은 것은 아니고, top-down방식도 좋습니다. 양자를 적절히 하여 좋은 성취이루시길 바랍니다.
------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.
------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.
Health Check 하는데 blocking 방식이 더 낫습니다.
아마도 아시겠지만... TCP/IP 프로그램을 돌려보면 실제로는 통신이 끊어졌는데, 에러코드만으로는 영 확신을 할 수 없는 그런 상태가 종종 나타납니다.
해결책은 어플리케이션 수준의 상태 확인 패킷을 보내는 것이 보통입니다.
그럴 경우 비동기식으로 짜면 매우 복잡한 코드가 됩니다.
그래서 차라리 동기식으로 하고 멀티쓰레드로 짭니다. 이건 제 경험담이고요.
그리고 이건 저도 그냥 본거라 근거 자료까지는 모르겠습니다만, 동기식 소켓의 throughput이 더 좋다는 글을 본 적이 있습니다.
아무래도 커널 차원의 컨텍스트가 더 무겁고 또 시그널로 보내기 위해서는 해당 어플리케이션의 프로세스나 쓰레드가 깨어날 때까지 대기해야 할 테니 그럴 것 같습니다.
도움이 되려는지...
non-block으로 하고
소켓을 그냥 non-block으로 만들고 select, connect, recv, send 등에서
그냥 error만 잡아서 처리해주면 안 되나요?
버퍼나 그런 것들까지 직접 관리해줘야 하는 정도인가요?
물론 클라이언트 수와 전송되는 데이터가 매우 적기 때문에
단순하게 block으로 그냥 select만 해줘도 충분하긴 하지만,
그래도 이번에 간단한 non-block 개념을 도입했으면 합니다.
----------------------------------------------------------------------------------------
Don't Feed the Trolls!
----------------------------------------------------------------------------------------
...
안될 이유가 있습니까? 논블록킹의 개념을 정확히만 파악하시고, 구현은 좋으실대로 하시면 되겠습니다.
이미 그 방안을 가지고 계신듯합니다.
좋은 결실 있으시길......
------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.
------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.
여러분들의 소스를
여러분들의 소스를 마음대로 참고(?)하여 다음과 같이 만들어 보았습니다 ㅡㅡㅋ
블락이 걸리는 함수에 대해서만 non-block을 해줬다가 다시 걸고,
멀티플렉스로 연결을 받아 접속을 처리하고 있습니다.
select가 파일디스크립터를 모두 검사하는 것이 마음에 들지 않아서
검사할 파일디스크립터를 리스트로 구현하려고 했지만,
귀찮은 마음에 그냥 돌립니다... 몇 개 안 될테니까요 ㅡㅡㅋ
앞으로 이것을 한 쓰레드로 하고,
DB에 저장하는 쓰레드로 전달하는 것을 구현해야겠네요.
----------------------------------------------------------------------------------------
Don't Feed the Trolls!
----------------------------------------------------------------------------------------
libevent 소스를
libevent 소스를 보세요.
-------------------------------------------------------------------------------------------------------
Life ... http://iz4u.net/blog/
------------------------------------------------------------------------------------------------
Life is in 다즐링
댓글 달기