C++/소켓통신

소켓 프로그래밍 주의점

gandus 2011. 5. 16. 17:14

출처 : http://ssb777.blogspot.com/2009/06/mfc.html
 


[MFC 소켓 프로그래밍시의 일반적인 주의점]

*) CSocket을 가능하면(절대라고 표현해도 될 정도죠) 사용하지 마세요.
- CSocket을 이용하여 프로그램 하시는 분이 있다면 존경받아 마땅한 분이죠...

왜냐면 CSocket은 Blocked Call이기 때문에 제대로 돌아가려면 Thread를 이용한 코딩이 되어야 하는데 거의 웬만한 경우에 배보다 배꼽이 크게 만듭니다...
옛날에는 유닉스 기반한 Telnet서버 등에서 이런 식의 Blocked Call을 Thread와 같이 사용했는데 실제적으론 문제가 많습니다. 가장 큰 문제는 시스템 리소스를 무지하게 잡아먹는다는 거죠
메모리 사용보다 가장 큰 문제는 Thread switching 오버헤드와 Thread 갯수 제한이죠...
1000명의 사용자가 접속하는 Telnet서버를 만들기 위해선 최소 1000개의 Thread를 만들어야 하는데 안되죠
1000개 Thread를 무리없이 돌릴 수 있는 프로그램이 몇 개나 될까요?
된다 치더라도 만약 각 Thread간의 Data Sync가 필요한 상황이 된다면 어찌될까요? 끔찍하겠죠?
- 이야기를 바꾸면 가능하면 Thread를 이용한 통신을 하지 말라는 말과도 같습니다... Thread는 필수일 경우에만 쓰시면 됩니다.
- 실제로 Thread를 이용한 통신을 하게 되더라도 결국엔 OS나 시스템 성능 때문에 대형 시스템에서 조차 ....
- Thread하나에 여러 개의 접속을 Async로 처리하게 될 수 있습니다. -> IOCP - 시스템의 성능을 한계까지 발휘했을 때 모든 처리를 각각의 Thread기반으로 처리했을 때와 한 개의 Thread에서 Async로 처리했을 때 당연 후자가 시스템을 가장 제대로 활용하게 될 수 밖에 없습니다.
*) CAsyncSocket 을 그대로 사용하지 마세요.
- Non Blocked Call이긴 하지만 그냥 사용해서 프로그램을 작성하면 끔찍한 프로그램 밖엔 만들 수가 없습니다.
일반적으로 CAsyncSocket을 사용하시는 분들의 특징이 데이터 수신은 받고 싶은 만큼만 받으면 되니 문제가 없는데 데이터를 송신할 때 문제를 야기시킵니다. 보내고 싶은 데이터를 그때 그때 바로 보내려고 시도하는데 문제는 OSI 세븐 레이어인지 하는 계통을 따라 데이터를 보내게 되는 통신 과정상 어디선가는 인터널 버퍼 오류 등의 여러가지 상황이 발생할 수 있습니다. 이때마다 .Send함수에 대한 예외 처리(혹은 그자리서 무식하게 메시지 루프를 돌면서 데이터가 전부 전달될 때까지 배째기)를 해야 하는데 프로그램이 커지면 수십 군데의 오류처리부가 존재하게 됩니다.
결국 무지하게 지저분한 코드가 될 수 밖에 없죠...
한 개의 함수 안에서 Receive와 Send가 번갈아 서너번 처리되어야 한다고 생각해보죠... 이중에 어디서 오류가 날지 누가 알겠습니까?
결국 개발자는 모든 Receive와 Send에 대하여 오류처리를 해야하죠.. 지금껏 정상이라고 믿고 작업했던 내용도 되돌려야 하죠
하지만 깊게 생각하셔야 할게 있습니다. .Send함수가 성공을 리턴했다고
상대방 프로그램이 그 데이터를 제대로 받았을까요? 혹은 받아서 처리하다가 죽었을 수도 있죠? 혹은 제대로 처리해서 결과를 리턴하는 도중에 인터넷 라인이 끊어지는 경우도 있을 수 있죠?
그런데도 수 십 개의 .Send함수 호출 바로 뒤에서 오류처리를 하실 겁니까?
진짜로 오류가 있는지 없는지는 내가 보낸 데이터에 대한 결과가 도착하기 전에는 알 수가 없는 거죠.
- 뒷부분에 자세한 이야기를....힌트를 말씀드리면 서로 신뢰할수 있는 프로토콜을 만들어야 합니다. 즉, 데이터를 수신한 곳에서 수신한 데이터가 올바른 것인지 판단해서 만약 잘못 받았으면 다시 보내달라고 해야합니다. 즉, 소켓오류로 처리하면 안됩니다. (제 경험에 의해서 드리는 말씀입니다.)
*) 가능하면 BSD소켓 API만을 사용하여 코딩하십시오...
- 뭐 여러가지 구질구질하게 이야기할 것 없이. BSD API만을 이용해서도 원하는 모든 것을 할 수 있습니다. (특히 CrossPlatform이 가능해 집니다. 짱!!!)
윈도우에서 잘 돌아가던 프로그램(예를 들어 ActiveX)을 유닉스(CGI프로그램으로 변경하여)에서 실행해야 한다고 생각해보죠.
MS의 API Extension은 꼭 필요한 경우에만 쓰시면 좋을 듯 싶군요. 예를 들어 오버랩드 IO정도 겠네요.(진짜 강력한 Winsock API입니다)
실제로 저같은 경우에 windows/free BSD/linux/solaris 등등에서 돌아가는 프로그램을 작성한 기억이 있는데 애초에 거의 BSD API만을
이용해 짰는데도 미묘한 API차이 때문에 고생을 많이 했습니다.
개인적으로 최소한 통신 API만큼은 MS API Extension들이 잘만들었다곤 생각지 않습니다.
- 윈도우즈 환경에서 기본적으로 사용해야 하는 MS구현 함수들
WSAStartup/WSACleanup/WSAGetLastError
- 오버랩드 IO를 사용할 때 써야하는 MS제공 함수들...
WSASocket(==socket)/WSAConnect(==connect)/WSAAccept(==accept)/WSASend(==send)
- 일반적인 BSD소켓 API함수들...
socket/connect/accept/send/recv/bind/listen/select/setsockopt/shutdown/closesocket
gethostbyname/inet_addr/inet_ntoa/ntohs/htons/FD_... 등의 utility함수 혹은 매크로...
- IOCTL함수 구현 - Win32(ioctl)/Unix계열(fcntl)