struct linger opt_ling = { 1, 0 }; // ling.l_onoff, ling.l_lingererr = setsockopt(hSocket, SOL_SOCKET, SO_LINGER, (const char*)&opt_ling, sizeof(opt_ling));
*) socket함수를 불러 소켓을 만들고 함수를 부르면 블럭이 됩니다. 어떻게 non-blocked call을 할 수 있죠?
클라이언트나 listen소켓 쪽에선 socket() 함수로 소켓을 만들자 마자 설정하면 됩니다.
당연 서버측에선 accept 혹은 WSAAccept 함수를 통해 얻은 소켓 핸들에 대하여 설정하면 되겠죠
뭐 단순히 소켓 핸들이 만들어지자 마자 항상 linger이나 non-blocked-IO 상태 등을 설정하시면 됩니다.
#ifdef WIN32u_long s_ulOPT = 1;err = ioctl(hSocket, FIONBIO, &s_ulOPT);if (err == 0) { // don't use SOCKET_ERRORreturn TRUE;}#else // !WIN32 - 유닉스 계열 OS들에서...int flags = fcntl(hSocket, F_GETFL);flags |= O_NONBLOCK;err = fcntl(hSocket, F_SETFL, flags);if (err != -1) { // don't use SOCKET_ERRORreturn TRUE;}#endif /* WIN32 */
*) OVERLAPPED IO가 잘 동작하지 않습니다.
OVERLAPPED IO 사용시 Write하는 쪽만 사용하면 됩니다. Read하는 쪽까지 사용하기엔 프로그램 구조에 문제가 많습니다. Read야 시간 남을 때 정해진 버퍼 사이즈안에서 계속 무작정 받아 두면 되고, 패킷 처리부에서 시간 날 때마다 가져다 처리하면 됩니다.
Q) OVERLAPPED IO결과가 성공이긴 한데 요구 되어진게 100 바이트 인데 50바이트만 보내고 50바이트는 못 보냈다고 나올 수 있나요? A) 현재까진 그런 경우는 본 적이 없습니다. 도큐먼트상으론 가능한데 All Or Nothing로 구현된듯 하네요... Q) select(fd_count, NULL, &fd_set, NULL, ...)을 이용하여 제대로 쓰기 가능 상태를 체크하는데 제대로 되지 않습니다.
마치 OVERLAPPED IO처리가 조금씩 지연되고 있는듯 보입니다. 어찌해야 하나요?
A) select(...) 호출 바로 앞에서 SleepEx(0, TRUE); 를 호출하여 OVERLAPPED IO결과가 프로그램에 전달될 수 있도록 해야 합니다.
필요한 경우 SleepEx() 함수 안에서 바로 OVERLAPPED IO콜백 함수가 불립니다.
Q) OVERLAPPED IO의 사용에 가장 큰 장점이 있다면 무엇?
A) 각 소켓 연결마다 필요한 고정 사이즈의 중간 Send용 버퍼의 크기제한/낭비가 없어지며 속도가 빠르다... -> Windows NT Platform에서는 궁극의 소켓인 IOCP를 사용해야 합니다.
*) 자기만의 TCP/IP 용 라이브러리를 설계하고자 하는 사람이 반드시 알아야 할 한가지가 있다면?
*) CSocket을 가능하면(절대라고 표현해도 될 정도죠
) 사용하지 마세요.
- CSocket을 이용하여 프로그램 하시는 분이 있다면 존경받아 마땅한 분이죠...
==> CSocket가 Blocked Call이기 때문에 쓰레드를 꼭 써야하는것도 아니죠....ui에 신경을 쓸필요가 없거나 소켓 옵션에 timeout을 걸어둘수도 있는 문제구욤....꼭 blockedcall이 나쁜건 아니죠..... 그리고 쓰레드을 이용한 코딩이 오브헤드가 그렇게 많지 않답니다. 그리고 telnet데몬들은 1user 1thread로 작성된게 거의 대부분이고 잘돌아 갑니다. 그리고 data sync도 따지고 보면 blocked나 non-blocked나 둘다 비슷할텐데요 ; *) 가능하면 BSD소켓 API만을 사용하여 코딩하십시오...
==> 멀티 플래폼이 아닌 socket프로그램이라면 굳이 bsd소켓 api만 사용하지 않아도 될것입니다. 포팅을 고려한다면...물론 BSD소켓만 사용하시는게 좋겠죠....
윈속2.0 api의 경우 많은 기능과 더 향상된 성능(미미하겠지만)을 발휘한답니다.
*) connect함수를 호출한 다음 언제 상대방이 제대로 접속이 이루어 진 것인가요?
==> 굳이 select을 사용해서 체크할 필요 없을듯합니다 connect의 리턴 값만 체크하는것만으로도 충분하다고 생각됩니다. 이부분은 왜 굳이 select을 사용해서 체크하는지 이유가 있다면 알려주세욤 (전 그냥 connect의 리턴값 체크로도 잘되었습니당) - 언제 소켓 접속이 끊어진 것입니까?
==> 어느쪽이든 끊고 싶은쪽에서 closesocket해버려도 상관없을듯한데요 만약에 보내구 있던중 데이터의 확실한 전송을 원하시면 linger 을 on해주면 .....음.....타임아웃 값을 조금 늘려주든지 하면 될겁니다.
*) 네트웍 서브시스템(혹은 인터넷 망사업자) 등등의 오류에 의한 강제 종료는 어찌 처리합니까?
==> 이럴경우에 보통 감지 되지 않습니다. ping/pong으로 체크를 하셔서 종료처리를 서버쪽혹은 클라이언트쪽에서 ...하는거시
*) 위의 graceful shutdown과정을 순서대로 밟고 제대로 처리했는데 바로 다시 재접속을 하면 접속이 안돼요. 어찌된 것인가요?
==> ??? 재접속을 하면 안되는 이유는 다른데 있는듯합니다...
*) OVERLAPPED IO가 잘 동작하지 않습니다.
==> 현재 서버구현에서 가장 많이 쓰이는게 iocp(windows nt기반에서)을 이용해서 overlapped i/o입니당..-,-a 그리고 보통 overlapped로 read/write한다구 해서 문제가 되는건 아님니당....오히려 성능이 좋다고 설명되어있습니다(win32네트워크프로그래밍;직접 벤치마킹해보진 않았음) 님이 말씀하신건 혹시 리눅스의 aio_의 단점이긴합니당; ==> 이건 저두 확실히 알지 못하지만 all Or Nothing라구 하긴 문제가 있지 않을까요 (10M~100M)을 보내보셍 그럼 100M가 가야하는데 그렇지 않을듯.....저건 스트리밍i/o인 tcp의 특성인거 같기도 하고.....이부분은 저도 확실하지 않습니당.
Q) select(fd_count, NULL, &fd_set, NULL, ...)을 이용하여 제대로 쓰기 가능 상태를 체크하는데 제대로 되지 않습니다.
마치 OVERLAPPED IO처리가 조금씩 지연되고 있는듯 보입니다. 어찌해야 하나요?
A) select(...) 호출 바로 앞에서
SleepEx(0, TRUE); 를 호출하여 OVERLAPPED IO결과가 프로그램에 전달될 수 있도록 해야 합니다.
필요한 경우
SleepEx() 함수 안에서 바로 OVERLAPPED IO콜백 함수가 불립니다.
*) select와 overlapped i/o와 아무 상관이 없으며 SleepEx을 쓰는 이유도 타당해보이지 않는뎅....;; 리고 버퍼에 넣는 이유는 오류처리의 불편함도 있을수 있겟지만 tcp가 스트리밍io 여서이기도 하고 버퍼링(똑같은 말이네...-..-;모아서 보내면 자잘히 많이 보내는것보다 좋겠져...-,-;)과 동기화등 다른 이유가 더 큰거 같은뎅; --이규승() *)접속이 끊어진건 오류뿐 아니라 recv가 0을 리턴해도 종료된게 아닌지요? --조해진 ->MSDN
*)몇몇 부분에서 수긍가지 않는것두있긴하지만 나름대로 각자의 스타일이라 생각하고 넘어갑니다 좋은글 감사합니다 --이규승 *)overlapped io에서 recv시 미리 사이즈를 주고 받아야 한다는 건 무슨 소리인지 이해가 안됩니다. 잘못아신듯 --최인호
답변 글을 달아 주셔서 감사합니다.
먼저 제가 글을 쓰는 상황에 대해서 밝히지 않은게 조금 문제가 된 듯 합니다.
어느날 웹서핑을 하다가 데브피아란 곳이 생각나서
;;; 들어와보니 의외로 소켓에 관한 질문을 하시는 분들이 꽤 되더군요..
전 지금까지 만 15년간 코딩을 해오고 있습니다. 그리고 그 중 소켓 코딩은 약 5년 동안 해왔고요...
물론 처음엔 CSocket/C
AsyncSocket/BSD API 를 이용한 전형적인 순서를 밟아서 나름대로 경험을 쌓은 것이고요.
제가 글을 처음 쓸 때는 이것저것 생각하지 않고 글의 제목대로 소켓코딩(정확히 말하면 자기만의 Library)을 함에 있어서 실제 제가 겪고 남의 질문에 답하는 과정에서 쌓인 생각이 자연스럽게 표출된 것입니다. 아무 생각없이 뜬금없이 글을 써 올린 제게 좀 문제가 있네요
ㅋ
* 위의 글에서 소켓 코딩은 그냥 TCP/IP(UDP 제외한...)를 이용한 코딩을 의미합니다.
* 최소한 CSocket/C
AsyncSocket은 써보고 대안을 찾는 사람을 대상으로 한 글입니다.
* 소켓코딩을 해서 실제 프로그램을 제작했는데 문제가 생긴 경우 혹시 프로그램상의 문제가 있다면 오류를 찾는데 도움을 드리기 위한 겁니다.
* 그래서 대부분의 글 내용이 BSD소켓 API를 이용한 async(non-blocked) call에 관한 내용입니다. 물론 win32 환경에서는 오버랩드 I/O를 사용하고 있다고 생각하시면 됩니다.
* 그리고
개인적으로 온라인 게임 서버/클라이언트, 메신저의 다자간 채팅 서버/클라이언트, 웹 서비스 회사의 ActiveX/CGI/인증서버 등등 많은 소켓 응용 프로그램을 제작한 경험상, 대부분의 상황이 접속 요구가 굉장히 빈번하고 수많은 오류 처리를 해야하는 상황하의 코딩들만 해보았기 때문에 CSocket/CAsyncSocket을 이용하는 경우나, 구조적 안정성이나 프로그래밍적인 편리성 등이 필요없는 상황(그저 대충대충해도 뭐든지 가능한;;)은 솔직히 전혀 생각해 본 적이 없었더군요... --정창모
논점1: blocked call / timeout / 오류처리
특수한 목적, 주로 1 대 1 접속을 목표로 하는 경우엔 CSocket이 아주 괜찮은 선택이긴 합니다.
단 상용제품 등으로 내지 않는 상황에서요.... 왜 그런고 하니 실제 작성된 프로그램이 안정성 있게 돌아가려면 수많은 예외처리를 해야하는데 CSocket을 이용한 프로그램의 속성상 프로그램 여기/저기서 send/recv를 남발하게 됩니다. 더구나 Blocked call 인 CSocket을 이용하면서 오류에 대처하기 위해 모든 송/수신 호출부에서 타임아웃을 건다고 생각해보죠... 조금 코메디가 되죠
자기 혼자 쓰는 프로그램이 아닌 경우는 거의 모든 경우에 안정성과 매끄러운 오류 처리 등이 필수적입니다. 결국 웬만한 정도의 안정성을 확보하기 위해서 넣는 오류코드가 장난이 아니게 되며 Async콜 사용에 비해 무지 깔끔했던 코드들이 결국은 누더기가 될 가능성이 농후합니다. 특히 CSocket의 사용시의 문제점은 그걸 사용해 무지하게 오랜 시간을 코딩했다 해도 개발자의 경험이 늘지 않는다는 겁니다. 아마도 궁극적으로
CSocket을 마스터한 사람이 쓰는 코딩 방식은 모든CSocket API에 극히 적은 타임아웃을 주고 마치 CAsyncSocket처럼 사용하게될 겁니다. - 1:1접속이 아닌 1:다 의 경우 mmorpg가 아닌경우엔 순간전송량이 많고 접속자수가 그리 많지않은(ftp나 file 관리서버)같은경우엔 blocked call이 훨씬 좋을수 있습니다.
->MMORPG 개발 경험상 무조건 ASynchronizatio이고 IOCP를 사용해야 합니다.
- 그리고 CSocket이 recv/send을 남발한다구 했는데 그건 Asyncsocket두 마찬가지아닌가요 이건 어떻게 소켓을가지고 프로그래밍 했느냐의 문제일듯...
- timeout에 대해서.... 실제루 그렇게 사용되구 있구요(ftp서버나 telnetd, httpd) 그리소 송수신 호출부에 타임아웃을 거는게 아니고 소켓의 옵션을 말했던겁니다.
논점2: winsock2을 사용할것인지 bsd호환 api을 사용할것인지?
전적으로 동의합니다... 하지만 엄청난 성능 향상(오버랩드 I/O는 정말 쓸만하죠
)이 이루어지는 것이 아닌데 굳이 윈도우즈에서만 사용되는 API만을 사용하면 웬지 이상하지 않느냐는 정도로 이해하시면 될듯...
엄청난
성능향상은 없지만 제가 알기론 overlapped I/O을 사용하는 WSASend/Recv의 경우엔 30%의 성능향상이 있으며...(network programming for mcrosoft windows와 개인적인 테스트)
iocp나 기타 winsock2에서만 지원하는 각각의 객체들도 winsock1대에서는 사용할수 없기때문에 성능상으로 따지고 보면 많은 향상이 있다는것입니다. 실제로 예전 테스트에서 select을 사용하는것보다 winsock2에서 제일 비슷한 eventselect가 성능상 우위에 있었습니다. -> 생각 보다 WInsock2 APID Eventselect 성능이 뛰어나다 만약 극단적인 성능대신 개발에 용이성으로 Tradeoff를 한다면 나는 EventSelect로 개발 한다.
논점3: overlapped i/o
소켓 프로그램 구조적으로 write는 오버랩드 I/O에 아주 잘 맞습니다. 하지만 문제는 read쪽인데 프로그램에서 read할 데이터의 사이즈가 명백한 상황에서는 오버랩드 I/O를 이용한 코딩이 아주 도움이 되겠죠.. 하지만 대개의 경우 소켓코딩에서는 읽어야할 데이터의 수가 미리 고정되어 있지 않습니다.-> 프로토콜 설계를 잘 해야 한다. 그저 상대방이 보내주는 데이터를 읽어야 하는데 패킷의 크기도 가변이 태반이기 때문에 미리 사이즈를 주고 읽어야 하는 오버랩드 I/O와는 맞지 않는다는 겁니다. 고작 고정 사이즈의 작은 패킷 헤더를 읽기 위해 쓰기엔 아깝죠... 다만 파일처리쪽에선 많이 다르겠죠. 파일처리시엔 이미 데이터의 크기를 알고 있기 때문에 사용하면 무지 편하겠죠...
참고로 overlapped i/o는 제가 님의 말씀을 듣고 찾아본결과 현재 수면위로 올라온 버그는 없습니다. 그리고 커맨드가 가변일경우에 아깝다구 했는데....왜 그런지 이해하기 힘들구 제 생각에 님 기법이 데이타 사이즈을 recv 그후에 데이터를 recv해서 파씽하시나 본데 그렇게 하지 않고
그냥 일정 버퍼크기만큼을 받아서 파씽하는 방법을 보통 사용하죠 (overlapped i/o시) 논점4: socket가 스트리밍i/o라는 말이었는뎅...
스트리밍 I/O 처럼 속도까지 필요한 경우엔 독립적인 Read/Write 쓰레드 까지 사용될 수 있으므로 동기화 때문에라도 버퍼의 필요가 극대화 되겠죠.
다들 아시는것처럼 데이터량이 많으나 적으나 버퍼링으로 얻는 이점은 많답니다; --이규승
-> 윈도우 OS Kernel에서도 결국은 데이터를 Page or NonpagePool Memory management that This point is good at use Buffer for Winsock application! -aiwisdom@gmail.com