컴퓨터공부

[펌] 소켓프로그래밍

achivenKakao 2005. 5. 30. 00:24
 
[펌] Win Socket을 이용한 Net 프로그램 | C, C++
2004.11.15 02:13
모그리(radius7) http://cafe.naver.com/mscs/411
『시지프스(Cezips) C/C++프로그래밍-MS-WINDOWS
제  목:[강좌] WinSock을 이용한 네트웍 프로그래밍 01           올린이:조재영
조재영님 자료를 허락없이 올렸습니다.. 읽으시고, 뭔가 얻으신것이 있다면 글을 쓰신 이에게
감사하는 맘을 갖는 것도 좋겠죠
 * 이번 게시물은 가벼운 마음으로 읽어주시면 됩니다. 하지만, 게시물 후반부에 나  오는 OSI 7 Layer는 꼭 이해를 해 주셔야 합니다. 네트웍에 대한 기초적인 구조  를 이해할 수 있는 부분이기 때문입니다. 또한 IP, 포트, 패킷에 관한 개념 이해  또한 필수입니다.[윈도우 소켓을 이용한 네트웍 프로그래밍]*[송수신 방식에 따른 분류]*[네트웍 토플로지]*[On Line / Off Line]*[OSI 7 Layer]*[인터넷에서 데이터는 어떻게 전송될까?]1. 소켓 프로그래밍을 위한 통신 개론. 통신이 뭘까요? 국어 사전에서 정확한 정의를 찾아 보지는 않았습니다만, 자신의 의견을 남에게 알리는 방법들을 통신이라고 할 수 있다고 생각합니다. 지금 여러분은 제 글을 읽고 계시고 저는 여러분과 저는 통신을 하고 있습니다. 이렇게 따지면통신의 방법은 아주 많죠? 전화, TV, 컴퓨터 통신, 인터넷등등 생각해 보면 꽤 많은 방법으로 인간은 소식을 전할 수 있고 전달 받을수 있습니다. 앞으로 여러분들과 같이 다루게 될 내용은 그 중 한 가지인 컴퓨터를 이용한 통신입니다. 많은 통신 방법 중 단지 하나를 다루는 것 뿐입니다. 항상 이점을 명심하세요. 통신은 자신의 의견을 남에게 알리는 한가지 방법일 뿐이라는 점. 그리고 그렇게 하려면 어떻게 해야 할까?에 대한 물음과 그에 대한 답을 찾아 보십시요. 그것이 통신 프로그램을 짜야할 여러분들이 앞으로 나가야할 방향입니다. 단지, 여러분들은 다른 사람들과 달리 컴퓨터를 이용하는 것뿐입니다. 아래에 나오는 내용들은 앞으로 여러분들과 같이 윈도우 소켓프로그램이라는 것을알아나가는데 그리 큰 역할을 하지는 않지만, 상식 차원에서 다룬 부분들입니다.꼭 외울 필요가 없는 부분도 있고 꼭 알야할 부분도 있습니다. 게시물 전반부에서 중요하다고 언급한 부분들만 중점적으로 봐 두시면 도움이 될 것입니다.-[송수신 방식에 따른 분류]---------------------------------------------------*심플렉스(Simplex)A -> B한 지점에서 다른 지점으로만 보낼 수 있는 방식입니다. 가장 좋은 예는 TV나 라디오 같은 통신 매체 같습니다. 물론 시청자 소감이나 방송국에 항의를 하면 양 방향통신이라고 생각 할수도 있겠습니다만...... ^^; 대부분 TV를 통해 한 곳에서 보내는 방송을 일방적으로 보고 듣기에 위와 같이 설명을 했습니다.*하프-듀플렉스( Half-Duplex )A -> B 또는 A <- B 양방향 통신이 가능하긴 하지만, 한 쪽에서 다른 쪽으로 통신 내용을 보내고 있을때 반대쪽은 받을수만 있고 보내지는 못하는 경우라고 생각하시면 간단하리라 봅니다. 마땅히 좋은 예가 떠오르지는 않지만, 우편 시스템을 생각해 보면 어떨까요?한쪽에서 편지를 쓰면 반대쪽은 편지를 받고 다시 반대쪽으로 답신을 하는 상황.양쪽으로 통신이 이루어지는 하지만, 동시에 이루어지지는 않는 경우죠.*풀-듀플렉스( Full-Duplex )A <-> B양 방향 통신이 가능한 경우입니다. 전화가 좋은 예겠군요. 생각해 보면 위의 용어들만이 낮설을 뿐이지 여러분들은 모두 한번씩은 경험해 보신 친근한 방식들이라 생각됩니다. 알게 모르게 여러분이나 저나 통신에 대해 많은것들을 알고 있다는 사실은 아래의 글들에서 또 확인하게 될 것입니다. 사실 누구나 생각할 수 있는 것 들일지도 모르겠습니다. 단지, 누군가 먼저 이론화 했을 뿐.=[송수신 방식에 따른 분류]===================================================-[네트웍 토플로지]-----------------------------------------------------------기억이 확실치는 않지만, 토플로지는 지형학을 뜻한다고 들었던것 같습니다. 어찌되었든, 잘 생각해 보면 네트웍의 구성도를 보면, 몇몇 특징적인 연결도(지형도)를그려낼 수 있습니다. 각각의 방식엔 장점 및 단점이 있습니다만 외우실 필요는 없습니다. ^^;*링  말 그대로 반지와 같은 구조입니다. 여러대의 컴퓨터가 서로 이웃된 컴퓨터와 선로를 통해 연결되어 있는 구조입니다. 장점은 어느 선로 하나가 끊겼을 경우에 통신에는 문제가 없다는 점이죠. 단점은 데이터 하나를 보내기 위해 여러 컴퓨터를 거친다는 점 이겠군요.*스타 어떤 중앙 서버 한대가 있고, 단말기 형태의 컴퓨터들이 서버에 연결되어 있는 경우죠. 불가사리를 연상하시면 좋을듯 하군요. 이 토플로지의 단점은 중앙 제어 장치에 문제가 생기면 모든 터미널 사이의 연결이 끊어져 버린다는 점 입니다. 하지만, 터미널이 몇 대가 고장나든 상관은 없겠죠? ^^;*버스 고속도로 휴게소A에서 휴게소 B로 물건을 배달하는 시스템을 생각해 보시는게 좋겠군요. 고속도로에 끊기는 곳만 없다면 어느 휴게소든 물건을 배달할 수 있겠죠? 마찬가지로 여러대의 컴퓨터는 하나의 선로를 공유하고 그 선로를 통해서 자신의 원하는 컴퓨터로 메시지를 보낼수 있는 방식입니다. 이 방식의 약점은 모두가 공유하고 있는 선로가 파손 되었을때 모든 시스템이 고립된다는 점이죠. 스타 방식에서 중앙 제어장치가 고장나듯이요. 위의 구조중 어떤 방식이 최선이라고 정의를 할 수는 없습니다. 역시 가장 중요한점은 가격대 성능비겠죠. 투자될 선로비가 컴퓨터보다 싼지 아닌지에 따라 선로의안정성이 중요한지 제어장치(컴퓨터)의 안정성이 중요한지에 따라 선택을 해야할문제니까요.=[네트웍 토플로지]===========================================================-[On Line / Off Line]--------------------------------------------------------*On Line 말 그대로 선이 연결되어 있는 경우입니다. 여러가지 예가 있겠죠? 은행에서 다른곳으로 돈을 보낸다든지 하이텔에 접속해서 데이터를 다운로드를 받는경우. 혹은 대화 방에서 채팅을 하는경우 전화 등등...... ^^; 위 예들의 공통점이자 Off Line과의 차이점은 어떤 선로를 통해 데이터를 주고 받는 다는 점입니다. 장점은 역시 즉각적인 답을 얻을수 있다는 점입니다만, 선로를 통해 보낼수 없는 것들이 더 많다는 점이겠죠. ^^;*Off Line 끊어진 선. (-_-;) 어떤 선로를 통한 통신이 아닌 경우를 생각하시면 되겠죠? 자주 하실지는 모르겠지만, 오프라인 모임이라든지 소포를 보내는 경우겠죠. 단점은 온라인과 반대로 즉각적인 답을 얻을수 없다는 점이지만, 선로를 통해 보낼 수 없는 데이터를 주고 받을 수 있다는 점이겠죠. 온라인 대화에서 느낄수 없는 사람의느낌이랄까요? ^^;=[On Line / Off Line]========================================================-[ OSI 7 Layer ]-------------------------------------------------------------네트웍 상에 연결되는 시스템의 이상적인 표준 모델을 정의한 계층입니다. 개념 이해가 중요합니다. 깊게 공부할 필요는 없지만, 7가지 계층의 관계와 실제 그 계층들이 실제 여러분들이 사용하시는 인터넷에서 어떤 역할을 하는지는 꼭 파악을 해 두셔야만 합니다. 제가 설명을 하려고 했지만, 어설픈 제 설명보다는 서점에 널려있는 네트웍 책 중 아무거나 한 권 잡고 보시면 될 부분이기에 설명은 생략합니다.참고로 다 보시기 귀찮으시면 아래 4가지 계층을 중점적으로 보십시요.1. 물리2. 네트워크/링크3. 전송4. 애플리케이션.위의 4가지 계층을 꼭 숙지하시고 다음 게시물을 읽어 주시기 바랍니다.=[ OSI 7 Layer ]=============================================================-[인터넷에서 데이터는 어떻게 전송될까?]--------------------------------------우선 몇가지 용어에 대한 정의를 해야할것 같습니다.*IP     : 네트웍 상에서의 주소.*Port   : IP로 들어오는 패킷을 구분지어주는 구분자(?)*Packet : 보낼 데이터를 적당히 잘라놓은 조각.좀더 다세히보도록 하죠.I P : 네트웍상에서의 주소라고 생각하시면 간단합니다. 당연한 이야기지만, 전화      를 하려면 전화번호가 필요하고 우편물을 보내려면 주소가 필요합니다. 이와      마찬가지로 컴퓨터사이의 통신에서는 IP라는 주소가 사용됩니다.      그 형식은 아래와 같습니다.      ex) 169.254.34.243 ( 0~255.0~255.0~255.0~255 )포트 : 주소만 안다고 물건을 원하는 사람에게 정확하게 전달할수 있을까요? 그       물건을 받을 사람의 이름이 있어야 정확히 전달이 될것입니다. 주소가 맞       아도 이사를 갔다거나 받는 사람의 이름을 알지 못하면 우편 배달부는 난감       할 것입니다. 같은 IP로 데이터들이 와도 포트에 따라 그 데이터들이 분류       됩니다. 컴퓨터로 생각하면 컴퓨터에 데이터가 수신되었을때, 그 데이터       가 사용될 프로그램을 구분 지을 구분자정도로 생각하시면 간단할 겁니다.       ex) 5001 ( 0~65535 )패킷 : 패킷은 우편물 정도로 생각하시면 간단합니다. 즉, 실제로 보낼 데이터라고       생각하시면 됩니다. 그 내용은 보내는 사람의 마음이겠죠? ^^; 우선 컴퓨터에 대한 설명을 하기전에 우리 일상을 생각해 볼까요? A지점에서 B지점으로 많은 사람이 이동한다고 가정을 해보죠. 이동 방법은 자동차, 기차, 비행기, 배 이렇게 4가지가 있다고 생각을 해 보죠. 같은 시간에 가장 많은 사람을 A지점에서 B지점으로 이동시킬수 있는 방법은 4가지 교통수단을 이용할 사람의 수를 적당히 분배하고 적당한 이동 경로를 지정하는 방법일 겁니다. 인터넷에서 데이터를 보내는 방법도 위와 크게 다르지 않습니다. A지점에서 B지점으로 데이터를 보낼 때효율적인 전송을 위해 그 데이터를 적당한 단위로 끊고 적당한 경로를 지정해 주면됩니다. 그럼 위의 경우를 용어로 정리를 해보겠습니다. 앞에서 이야기 한 부분과 크게 다른 부분은 없지만, 용어 파악을 위해 다시 한번쓰겠습니다. 어려분 컴퓨터(이하 A)의 어떤 데이터를 다른 컴퓨터(이하 B)로 보낸다고 가정을 해 보죠. A에서 데이터를 B로 보내기위해 우선은 데이터를 알맞은 크기로 즉, 패킷 단위로 자릅니다. 그리고 그 패킷에는 이 찾아가야 할 컴퓨터의 네트웍상의 주소(IP)가 있어야겠죠? 그런데, IP가 지정되었다고 B를 찾아갈때 아무렇게나 가지는 않겠죠? 당연히 가장 빠르게 갈 수 있는 길을 찾아내서 그 길로 가야 할 것입니다. 어찌되었든, 보내온 데이터 즉, 패킷이 다 모아지면, OK신호를 보내고 그 데이터는 B에서 인정이 되는거죠. 그런데, 만약 통신 프로그램에 IP만 있다면 컴퓨터 하나당 통신 프로그램은 단 하나밖에 존재할 수 없을 것입니다. 그걸 보완하기 위한 개념을 포트라고 생각을 하시면 됩니다. ^^; 즉, IP로 상대방의 컴퓨터 주소를 적어주고 포트로 받을 프로그램을 지정해주는 거죠.=[인터넷에서 데이터는 어떻게 전송될까?]======================================-[자신의 IP확인하기]--------------------------------------------------------- 당연한 이야기지만 네트웍 프로그램을 하려면 기본적으로 통신 장치가 있어야합니다. 모뎀, 랜카드, 두루넷이나 드림라인같은 서비스에 가입등의 방법으로 자신의IP를 할당 받아야합니다. 모뎀의 경우는 전화접속 네트워킹으로 통신사에 접속을 하고 IP를 배당받는 방법이 있겠고, 랜카드는 장착만 해도 가상의 IP를 얻을수 있습니다. 또하나의 방법은 두루넷이나 드림라인같은 전용선 업체에 가입해서 IP를 할당받는 방법입니다. 그냥 랜카드만 있으면 가상으로 밖에 체크가 않되지만 IP를할당 받으면, 실제로 데이터를 주고받아 볼수 있습니다만 랜카드만으로 가상의 테스트를 해 보는 방법도 나쁘지는 않습니다. 저도 처음엔 그렇게 했었습니다. 그래서 앞 게시물에서 랜카드를 싸구려라도 하나 정도는 꼭 구비해 두라고 했었죠.노파심에서 하는 이야기지만, 운영체제에 따른 아래의 테스트를 꼭 해주십시요.그리고 자신의 IP를 확인하는 법을 꼭 찾으십시요.윈도우 98과 윈도우 2K의 경우 조금 다릅니다.윈도우98 : 시작버튼을 누른다.           실행을 선택.           winipcfg를 입력후 엔터하시면 프로그램이 하나 뜹니다.           모뎀이 있으신분은 PPP Adapter가 있을겁니다. 전화전속 네트워킹으로           연결을 하신상태면 할당받은 IP가 나올테고, 아니면 알수 없는 숫자들           이 나와있습니다. 만약 랜카드만 있으시면, PPP Adapter가 없고 대신           랜카드와 관련된 정보가 보일겁니다. 모뎀과 랜카드가 같이 있으시면           PPP Adapter콤보 박스를 드랍다운 시켜보십시요. 나옵니다. 그리고 선           택하면, IP정보를 확인할수 있습니다.           또 하나의 방법. 그냥 도스창에서 ipconfig입력을 넣습니다.윈도우2K : 시작 버튼을 누른다.           보조프로그램           명령 프롬프트           도스창에서 ipconfig라고 칩니다.           IP, Subnet Mask, Gateway가 나옵니다만 우리가 필요한 것은 IP뿐           랜카드만 달랑 달아 놓으셨다면, 자동으로 잡힌 IP가 보일겁니다.           만약 IP를 할당 받으셨다면 할당된 IP가 나오겠죠? ^^;Tip : 아마도 랜카드만으로 가상의 네트웍 환경을 만들어 쓰실 분들이 많을겁니다.      현실적으로 모뎀으로 하기엔 무리고 그렇다고 IP 서비스 가 전역으로 퍼진      상태가 아니니까요. 그럴경우면 윈도우 2K에서 랜카드를 설치하고 하십시요.      윈도우 98은 시동될때마다 가상의 IP주소를 계속 바꿉니다. 나중에 이문제는      꽤 귀찮아집니다. 하지만 윈도우 2K는 전혀 변함이 없져. 한 번 설정된 값을      계속 유지합니다. 하지만 윈도우 98에서도 해결법은 있습니다. ^^;      네트워크 환경에서 오른쪽 버튼을 누르고 등록정보를 선택합니다. TCP/IP      등록 정보를 선택하고 그 안에서 IP정보를 선택합니다. 여기에 IP를 자동으      로 할당함이라는 라디오버튼을 해제하고 IP를 강제로 지정해 버리는겁니다.      그러면 그 IP로 계속 유지됩니다.=[자신의 IP확인하기]========================================================= 쓰고보니 정말 날림 기본 정리군요. --; 제가 네트웍 프로그램에 처음 접했을때 가장 어려웠던 점이 용어 문제였습니다. 알고 보면 별것도 아니었는데, 처음에 하나 하나 이해를 해 나가는데, 용어하나를 모르면 이빨이 하나 빠져버린 느낌이었습니다. 위의 내용들을 뼈대(부실한 ^^)로 서점에서 좀 더 자세한 정보를 얻어 놓으신후에 다음 절로 넘어 가심이 좋을 듯합니다. 윈도우 소켓 프로그램만을 하는데는OSI 7 Layer같은게 실제로 중요하지는 않지만 알고 있을경우와 그렇지 않을 경우상당한 차이가 있습니다. 개인적으로 그 경험을 해봤기에 여러분들께 감히 하시라고 지속적으로 이야기를 하고 있습니다. ^^;[주의] 다시 하번 강조하지만 OSI 7 Layer, IP, 포트, 패킷은 꼭 이해를 해 주셔       야합니다. 그리고 IP확인도 꼭 해보세요『시지프스(Cezips) C/C++프로그래밍-MS-WINDOWS 강의란 (go CEZIPS)』 125번 제  목:[강좌] WinSock을 이용한 네트웍 프로그래밍 02                 올린이:불의악마(조재영  )    00/09/05 16:04    읽음:338 관련자료 없음 ----------------------------------------------------------------------------- 제  목:[강좌] WinSock을 이용한 네트웍 프로그래밍 #02   관련자료:없음  [1730] 보낸이:정현호  (비주얼씨)  2000-07-18 20:52  조회:436*////////////////////////////////////////////////////////////////////////////// 제 글들은 절대로 상업적 목적으로 사용될수 없으며, 저자인 저의 허락없    //// 이는 그 어느곳에도 게시를 할 수 없습니다.                               //////////////////////////////////////////////////////////////////////////////*기타 궁금한 사항은 아래로 문의를 바랍니다.ashulam@hitel.netashulam@isoft.co.kr* 이번 게시물에선 앞으로 여러분들과 다루게 될 윈도우 소켓에 대해 설명을 하겠   습니다. 앞으로 가장 자주 쓰이게 될 개념이므로 확실하게 이해를 해 두서야 합   니다. [윈도우 소켓을 이용한 네트웍 프로그래밍][윈도우 소켓이 뭐길래?][파일 포인터를 먼저 봐요.][윈도우 소켓과 파일 포인터의 관계는?]2.윈도우 소켓이란?[윈도우 소켓이 뭐길래?] 앞으로 여러분과 제가 가장 자주 다루게 될 물건(?)인 소켓은 아래와 같이 선언합니다. SOCKET   MySocket;간단하죠? 그럼 SOCKET이 어디에 어떻게 선언이 되어있는지 확인해 보도록하죠.컴파일러(VC++ 기준)의 인클루드 폴더의 WinSock.h를 보시면 35번째 줄에 아래와 같이 선언이 되어 있습니다.typedef u_int           SOCKET;한마디로 "unsigned int"였던 것이었습니다. ^^; 윈도우 계열 네트웍 플밍의 핵심인 윈도우 소켓이라는게 unsigned int라니 조금은 실망한 분들이 많을듯 하군여. 저도 처음엔 무슨 대단한 구조체인줄 알았는데, 막상 찾아보니 저 모양이더군요.[파일 포인터를 먼저 봐요.] 윈도우 소켓을 보기전에 파일 포인터를 생각해 보도록하죠. 파일을 제어하기 위해 파일 포인터 사용하셨던 기억을 되살려 보도록 하죠. FILE   *file; file = fopen( "MyText.Txt", "rb" ); fread( &Val, size, count, file );     .     .     . fwrite( &Val, size, count, file ); fclose( file ); 보통 위와 같이 했었죠? 저만 위와같이 했나요? 어찌되었든, fopen이라는 함수를 통해 file이라는 포인터는 MyText.txt라는 파일을 대표하는 ID가 되었습니다. 그 뒤에 파일에서 데이터를 읽어낸다든지, 파일로 데이터를 기록한다든지 할 때, 항상file이라는 ID를 이용하죠. 파일을 다 사용했으면, fclose라는 함수로 file이라는 ID는 더이상 쓰지 않겠다고 알려줍니다. 왜 갑자기 파일 포인터를 이야기 했냐면?앞으로 여러분께서 사용하실 윈도우 소켓이 위의 예에서 다룬 file 포인터와 아주 비슷하게 사용되기 때문입니다. 다음 게시물에서 구체적으로 어떻게 다룰지를 이야기 하겠습니다. 현재 게시물에서는 위에 제가 이야기한 정도만 아시면 충분하리라 생각합니다.[윈도우 소켓과 파일 포인터의 관계는?]아래에 실제로 소켓이 어떻게 쓰이는지 예를 보이겠습니다. 위의 파일 포인터 사용과 어떤점이 비슷한지 유심히 살펴 보십시요. 처음보는 함수들의 기능에 대해서는 몰라도 됩니다. 바로 다음 게시물에서 자세히 이야기하겠습니다. 지금은 문장 형식에만 관심을 가지고 보십시요. SOCKET이 어떻게 쓰이는지...... ^^;//소켓의 역할은?-------------------------------------------------------------SOCKET         ServerSocket;   //서버소켓SOCKADDR_IN    ServerAddress;  //주소에 관련된 구조체ServerAddress.sin_family = AF_INET;ServerAddress.sin_addr.s_addr = INADDR_ANY; ServerAddress.sin_port = htons( ServerPort=5001 );//소켓을 생성합니다. 파일 포인터의 FILE *file과 비슷합니다.ServerSocket = socket(AF_INET, SOCK_STREAM,0); //파일 포인터로 어떤 파일을 지정하는 부분과 비슷합니다. fopen()과 비슷한//기능을 합니다.bind(ServerSocket,(struct sockaddr*)&ServerAddress,sizeof(ServerAddress));listen(ServerSocket,SOMAXCONN);//fwrite나 fread와 비슷하게 실제로 원하는 작업을 가능하게 해 주는 함수들.send( ServerSocket, SendMessage, SendSize, 0 );     .     .     .//소켓을 다 쓰면 닫습니다. fclose()와 비슷합니다.closesocket( ServerSocket );//소켓의 역할은?============================================================= 나름대로 파일 포인터와 비슷하다고 억지로 말하고 억지로 끼위맞춘 부분도 없지 않아 있기는 합니다만, 파일을 다뤄 보셨다면, 위의 예가 오히려 쉽게 오지 않을까생각합니다. 저도 처음에 위의 예를 들어 설명을 들었을때 쉽게 느껴진듯 하고요. 다음 게시물부터는 실제로 윈도우 소켓을 초기화 해보겠습니다.이번 게시물에서 특별히 주의할 사항은 없습니다. 단지, 윈도우 소켓이 어떤 형태고 실제 문법에서 어떻게 사용되는지에 대해 한 번 ?어 보시는 정도면 됩니다.『시지프스(Cezips) C/C++프로그래밍-MS-WINDOWS 강의란 (go CEZIPS)』 126번 제  목:[강좌] WinSock을 이용한 네트웍 프로그래밍 03                 올린이:불의악마(조재영  )    00/09/05 16:04    읽음:341 관련자료 없음 ----------------------------------------------------------------------------- 제  목:[강좌] WinSock을 이용한 네트웍 프로그래밍 #03   관련자료:없음  [1731] 보낸이:정현호  (비주얼씨)  2000-07-18 20:52  조회:398*////////////////////////////////////////////////////////////////////////////// 제 글들은 절대로 상업적 목적으로 사용될수 없으며, 저자인 저의 허락없    //// 이는 그 어느곳에도 게시를 할 수 없습니다.                               //////////////////////////////////////////////////////////////////////////////*기타 궁금한 사항은 아래로 문의를 바랍니다.ashulam@hitel.netashulam@isoft.co.kr*윈도우 소켓의 핵심이라 할 수 있는 소켓 초기화 부분에 대해서 다루게 됩니다. 비주얼씨를 가지신분은 MSDN을 참조하시고 윈속 책을 가지신분은 책을 참고 하셔서각 함수들의 역할을 분명히 이해해 두셔야만 합니다. C언어의 문법을 배우는 부분과 비슷하고 중요도도 그와 비슷합니다. ^^; 외워야 하는 부분도 많고 테스트해 볼 부분도 많기에 여러분이나 저나 다 지치겠군요. ^^;[예제코드 프로젝트 구성 및 사용법] 이 게시물에 관한 예제는 Network\TCP\Server에 있습니다. 프로젝트에 ws2_32.lib wsock32.lib 파일을 재정의 하셔야합니다. 사용법] server 서버프로그램의IP주소 서버프로그램의포트번호(2000-65535까지) 실행하시면 어딘가에서의 연결을 기다린다는 메시지만을 출력합니다. 다음 게시물에서 다룰 클라이언트 프로그램을 실행하시면 연결을 받고 프로그램을 종료합니다. 만일 자신의 IP가 111.222.111.222라면? server 111.222.111.222 5001 client 111.222.111.222 5001[윈도우 소켓을 이용한 네트웍 프로그래밍]*WS2_32.DLL을 초기화해요~*윈도우 소켓을 만들어 봐요*바인드가 뭘까??*누군가의 연결을 기다려 봐요.*데이터를 보내봐요~~3. 윈도우 소켓 초기화와 서버 프로그램이번 게시물은 서버 프로그램에 관한 이야기입니다. 말이 거창하군요. ^^; 보통의 경우 통신시 서버와 클라이언트로 구성이 됩니다. 이번 게시물은 서버를 구동하기 위해 어떤식으로 윈도우 소켓을 초기화하고 나열하는지 보게될 것입니다. 당연히 다음 게시물은 클라이언트겠죠. ^^; 이번 게시물이 아마 전체 게시물중 최고의 중요도를 자랑한다고 해도 과언이 아닐겁니다. 하나 하나 저도 아는걸 모두 설명할테니 꼭 꼭 한번씩 타이핑해 보시고 컴파일도 해 보시고 이상하다 싶은건 하나하나 꼭 건들여 보십시요. 정말 중요합니다. 참!! 컴파일이나 소스에 관한 제어는 다음게시물까지 읽으신후 초기화에 관련된 함수를 잘 보시고 나서 보시는게 좋을겁니다. 서버와 클라이언트의 전체적인 개념과 두 프로그램의 공통점과 차이점을 확인해 보는 게 중요합니다.[WS2_32.DLL을 초기화해요~]윈도우 소켓을 시작하기 전에 윈도우에서 윈도우 소켓과 관련된 DDL파일을 초기화 해 주어야합니다. MSDN에 따르면 WS2_32.DLL를 초기화 한다고 하더군요. 그 과정은아래와 같습니다. 거의 아래의 경우를 벗어나는 일은 없을겁니다.DLL에 관한 설명을 곁들인다.//WSAStartup()사용하기.------------------------------------------------------WSADATA        wsaData;if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR){    printf( "WSAStartup설정에서 문제 발생.\n" );}소켓에 관련된 함수들을 잘 사용합니다.WSACleanup();//WSAStartup()사용하기.======================================================윈도우 소켓을 사용하시기 위해 위와같은 과정을 거칩니다.WSAStartup은 WS2_32.DLL을 초기화 하는 함수입니다.WSAStartup( 버전, WSADATA구조체의 포인터 );버전 : 보통 0x202를 씁니다. 거의 디폴트죠. 버전에 관한 인자입니다.WSADATA의 구조는 아래와 같습니다.typedef struct WSAData {   WORD                    wVersion;   WORD                    wHighVersion;   char                    szDescription[WSADESCRIPTION_LEN+1];   char                    szSystemStatus[WSASYS_STATUS_LEN+1];   unsigned short          iMaxSockets;   unsigned short          iMaxUdpDg;   char FAR *              lpVendorInfo;} WSADATA, FAR * LPWSADATA; WSACleanup은 WS2_32.DLL의 사용을 끝내겠다고 알리는 함수입니다.int WSACleanup( void );wVersion : 버전입니다.wHighVersion : 버전입니다. 보통은 wVersion과 같은 값을 갖습니다.szDescription[WSADESCRIPTION_LEN+1] : 현재 소켓에 대한 설명입니다.szSystemStatus[WSASYS_STATUS_LEN+1] : 현재 상태를 나타냅니다.unsigned short          iMaxSockets : 나중에 채워지는 값입니다만 2.0이후에는                                      무시되는 값으로 알고 있습니다.unsigned short          iMaxUdpDg   : 2.0이상에서는 사용되지 않습니다.char FAR *              lpVendorInfo: 2.0이상에서는 사용되지 않습니다만, 1.1                                      버전에서는 사용됩니다. 어디에 쓰이는지                                      는 저도 모릅니다. ^^;실제로 뽑아볼 값은 wVersion정도입니다. ^^; 결과는 아래에..... ^^;Version:202               :버전HighVersion:202           :버전Description:WinSock 2.0   :버전을 문자열로 뽑을. -_-;SystemStatus:Running      :현재 윈도우 소켓의 상태를 나타냄.MaxSocket:0               :2.0이상에는 설정시 무시되는 값. -_-;MaxUdpDg:0                :1.1에서만 쓰인다는데 어디에 쓰는지 저도 모릅니다.[윈도우 소켓을 만들어 봐요]보통 사용법은 아래와 같습니다.//윈도우 소켓을 만들어 봐요~-------------------------------------------------WSADATA        wsaData;SOCKET         ServerSocket;   //소켓을 선언합니다.SOCKADDR_IN    ServerAddress;  //소켓의 주소 정보를 넣는 구조체입니다.unsigned short ServerPort = 5001;if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR)    printf( "WSAStartup설정에서 문제 발생.\n" );ServerAddress.sin_family = AF_INET;            //반드시 AF_INET이어야합니다.//IP주소값. INADDR_ANY는 아무거나입니다. ^^;ServerAddress.sin_addr.s_addr = inet_addr( "210.106.224.142" );              ServerAddress.sin_port = htons( ServerPort );  //포트번호//소켓을 만듭니다. 자세한 설명은 아래에......ServerSocket = socket(AF_INET, SOCK_STREAM,0); //if( ServerSocket == INVALID_SOCKET ) //에러 발생시 문구 출력.{    printf( "소켓을 생성할수 없습니다." );}윈도우 소켓 관련 함수들을 잘 씁니다. ^^;closesocket( ServerSocket ); //소켓을 닫습니다.WSACleanup();//윈도우 소켓을 만들어 봐요~=================================================SOCKADDR_IN의 구조는 아래와 같습니다.struct sockaddr_in{    short              sin_family; //AF_INET이어야만 합니다.    unsigned short     sin_port;   //포트 번호    struct   in_addr   sin_addr;   //IP주소 EX) "169.254.34.243"    char               sin_zero[8];//SOCKADDR과 치환할때 같은 사이즈를 만들기                                   //위해 8바이트의 공란이 있습니다. 무의미.};socket()은 소켓을 초기화 하는 함수입니다. 당연한가요? ^^;SOCKET socket ( int af, int type, int protocol );af : 주소 계열에 대한 기술. 거의 AF_INET이 디폴트type : 아래에 구 값중 하나가 들어갑니다.       SOCK_STREAM : TCP프로토콜을 사용할때 씁니다. 양쪽이 확실한 연결을 해                     놓고 쓰는 방식입니다. 전화와 비슷하죠.       SOCK_DGRAM :  UDP프로토콜을 사용할때 씁니다. 특정한 연결 없이 그냥 보                      내는 겁니다. 우편물을 보내는 방식과 비슷합니다.protocol : 보통 0을 넣습니다. 저도 의미는 모릅니다. ^^;closesocket()은 특정한 소켓을 닫는 기능을 합니다.int closesocket( SOCKET s ); [바인드가 뭘까??]바인드는 위에서 지정한 IP번호와 포트를 소켓과 연결 지어주는 과정이라고 생각하시면 됩니다. 파일 포인터를 생각해 보시면 쉬울듯 하군요.file = fopen( "파일이름", "옵션" ); 이렇게 선언하면 file은 어떤 파일과 그에 대한 접근 방식을 알려줍니다. 바인드도 마찬가지 입니다. 실제 예를 보죠.if( bind(ServerSocket,(struct sockaddr*)&ServerAddress,sizeof(ServerAddress)     ) == SOCKET_ERROR )     printf( "bind() failed with error %d\n",WSAGetLastError() );ServerAddress는 앞에서 선언한 내용과 같다고 가정합니다. 즉, IP는 169.254.34.243이고, 포트번호는 5001입니다. 바인후 앞으로 ServerSocket은 컴퓨터의 "169.254.34.243"번 IP의 5001포트를 나타내는것과 같습니다. 다시 강조하지만, 파일 열때를 잘 생각해 보세요. 거의 비슷합니다. ^^;[Listen으로 들어 봐요 -_-;]서버의 경우 연결을 받아들이는 경우가 많습니다. 연결 신호가 동시에 많이 왔을때는 특정 버퍼에 저장을 해두고 연결을 해 줘야 하는 경우가 생기게 마련이죠. 소켓에 그 버퍼의 크기를 지정하는 부분이라 보면됩니다. SOMAXCONN는 그 컴퓨터의 하드웨어에서 사용가능한 최대의 값을 의미합니다. 디폴트값입니다. ^^;if( listen(ServerSocket,SOMAXCONN) == SOCKET_ERROR )     printf( "listen함수 설정을 실패했습니다.\n" );참고로 listen의 두번째 인자에 대한 값은 당연히 최대값을 잡는게 당연한게 아닐까요? 괜히 작게 잡을 이유는 없죠. 하드웨어가 지원하는 최대값을 넣는건 너무나 당연한 거죠. 위와 같이 쓰는건 당연한거죠. ^^;[누군가의 연결을 기다려 봐요.]지금까지의 과정들을 아래에 나열하죠. ^^;WSAStartup();socket();bind();listen();연결을 기다려봐요~ <=여기입니다. ^^;closesocket();WSACleanup();이제 서버프로그램은 클라이언트의 접속만을 기다리면 되는겁니다. 그 함수는 다름아닌 accept입니다!! 실제 코드를 볼까요? ^^;int           AddressSize = sizeof( ClientAddress ); //주소 크기를 저장하는                                                       //변수.SOCKADDR_IN   ClientAddress; //접속한 클라이언트의 주소 정보를 담을 구조체.SOCKET        ClientSocket;  //클라이언트 소켓.ClientSocket = accept( ServerSocket,(struct sockaddr*)&ClientAddress,                        &AddressSize );SOCKET accept ( SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen );s : 접속을 받아들일 소켓( 서버의 소켓 )addr : 접속한 클라이언트의 주소를 담을 구조체입니다.        예를 들어 아래와 같다면......       서버 : "169.254.34.243", port : 5001;       결과는 아래와 같습니다. 접속자의 정보를 얻어오는 겁니다.       ClientAddress.sin_family => AF_INET       ClientAddress.sin_family => 5002       ClientAddress.sin_family => "169.254.34.244"AddressSize : 주소를 얻어올 구조체의 크기를 넣습니다.즉, accept로 접속한 클라이언트의 주소와 소켓을 모두 알수 있습니다. 중요한 건 소켁입니다. ^^; 실제로 데이터를 클라이언트로 보낼때 사용하는 함수에 필요한 인자는 소켓이니까요. ^^; 즉, ClientSocket은 받아들이는대로 연결이 끊어지기 전까지는 어디에 저장을 해 두어야 한다는 이야기겠죠. ^^;accept함수가 나온김에 블럭킹과 논 블럭킹에 대한 이야기를 참고로 하겠습니다.블럭킹은 일종의 무한루프라고 보면됩니다. accept함수가 그런데요. accept함수를 사용하면 연결이 들어올때까지 더 이상의 진행없이 그곳에 멈춰 버립니다. 그리다다 연결이 오면 계속해서 진행이 되는거죠. 이런 상황을 블럭킹모드라하고 그 반대가 논 블럭킹이죠. 그냥 지나가 버리는..... ^^; accept가 그 대표적인 예죠.이와 같은 함수를 쓰시다가 어? 다운인가? 하는 생각을 하실까봐 노파심에서 이야기를 합니다.[데이터를 보내봐요~~]이제 연결을 위한 기본적인 것이 다 되었습니다. 통신을 위한 서버가 만들어졌고, 어떤 클라이언트에서 누가 연결을 했는지에 대한 답이 나왔습니다. 이제는 보내고 받기만 하면 네트웍의 정말 기본적인 것이 다 되는 겁니다. ^^; 마지막 두 함수는바로 send(), recv()였던것입니다!! ^^;int send ( SOCKET s, const char FAR * buf, int len, int flags );s : 데이터를 받을 소켓. 지금까지의 예를 보면 서버에 접속한 클라이언트인    ClientSocket을 넣으면 좋을듯합니다. ^^; ClientSocket으로 데이터를 보내는     거라고 생각하시면 됩니다.buf : 실제 보낼 데이터의 버퍼의 포인터len : 보낼 데이터의 크기.flags : 옵션입니다만 지금은 그냥 "0"으로 알고 있어주십시요. ^^;리턴값 : 실제로 보낸 데이터의 바이트수.int recv ( SOCKET s, char FAR* buf, int len, int flags );s : 데이터를 받을 소켓. 지금까지의 예를 보면 서버에 접속한 클라이언트인    ClientSocket을 넣으면 좋을듯합니다. ^^; SOCKET s에서 데이터를 받는다고 생    각하시면 됩니다.buf : 실제 데이터를 받을 버퍼의 포인터len : 실제 데이터를 받을 버퍼의 크기flags : 옵션입니다만 지금은 그냥 "0"으로 알고 있어주십시요. ^^;리턴값 : 실제로 보낸 데이터의 바이트수.실제 사용을 어떻게 하는지 볼까요?[Send]char SendMessage[6] = "Test!";int  SendSize = 6;int  ActualSendSize;ActualSendSize = send( ClientSocket, SendMessage, SendSize, 0 );[Recv]int  retval;char Buffer[999]; //적당히 큰 버퍼를 잡아줍니다.retval = recv( ClientSocket, Buffer, sizeof Buffer, 0 );휴우~~ 우선은 여기까지입니다. 정말 소켓의 기본중에 기본만 보신겁니다. ^^;어때요? 어려운가요? 당연히 처음 보시는분은 외울게 많아서 어렵게 느껴질수도 있을겁니다만, 하나하나 천천히 잘 보시면 분명히 전부 이해하실수 있을겁니다. 네트웍에 관한 이론을 잘 이해해 두셨다면 위의 내용들은 이론을 코드로 옮긴것에 불과하니 잘 따져보시면 어렵지 않게 이해할 수 있을 겁니다.실제코드는 아래에 있습니다. 꼭 숙지하십시요!!//서버 코드------------------------------------------------------------------#include <stdio.h>#include <windows.h>void main(){    WSADATA        wsaData;    SOCKET         ServerSocket;   //소켓을 선언합니다.    SOCKADDR_IN    ServerAddress;  //소켓의 주소 정보를 넣는 구조체입니다.    unsigned short ServerPort = 5001;    if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR)    {        printf( "WSAStartup설정에서 문제 발생.\n" );        WSACleanup();        exit( 0 );    }    //반드시 AF_INET이어야합니다.    ServerAddress.sin_family = AF_INET;                //IP주소값. INADDR_ANY는 아무거나입니다. ^^;    ServerAddress.sin_addr.s_addr = inet_addr( "210.106.224.142" );     ServerAddress.sin_port = htons( ServerPort );  //포트번호    //소켓을 만듭니다. 자세한 설명은 아래에......    ServerSocket = socket(AF_INET, SOCK_STREAM,0); //    if( ServerSocket == INVALID_SOCKET ) //에러 발생시 문구 출력.    {        printf( "소켓을 생성할수 없습니다." );        closesocket( ServerSocket );        WSACleanup();        exit( 0 );    }    if( bind(ServerSocket,(struct sockaddr*)&ServerAddress,sizeof(        ServerAddress) ) == SOCKET_ERROR )     {        printf( "바인드를 할 수 없습니다." );        closesocket( ServerSocket );        WSACleanup();        exit( 0 );    }    if( listen(ServerSocket,SOMAXCONN) == SOCKET_ERROR )     {        printf( "listen함수 설정을 실패했습니다.\n" );        closesocket( ServerSocket );        WSACleanup();        exit( 0 );    }    SOCKET ClientSocket;    SOCKADDR_IN ClientAddress;    int AddressSize = sizeof( ClientAddress );    printf( "서버로의 연결을 기다리고 있습니다.\n" );    if( (ClientSocket = accept( ServerSocket,(struct sockaddr*)&ClientAddress        , &AddressSize )) == INVALID_SOCKET )    {        printf( "Accept시 문제 발생.....\n" );        getchar();    }    else    {        printf("접속 IP: %s, 포트 : %d\n", inet_ntoa        (ClientAddress.sin_addr), htons(ClientAddress.sin_port)) ;    }    closesocket( ServerSocket ); //소켓을 닫습니다.    WSACleanup();    printf( "서버 프로그램이 종료 되었습니다.\n" );    getchar();}//서버 코드==================================================================『시지프스(Cezips) C/C++프로그래밍-MS-WINDOWS 강의란 (go CEZIPS)』 127번 제  목:[강좌] WinSock을 이용한 네트웍 프로그래밍 04                 올린이:불의악마(조재영  )    00/09/05 16:04    읽음:268 관련자료 없음 ----------------------------------------------------------------------------- 제  목:[강좌] WinSock을 이용한 네트웍 프로그래밍 #04   관련자료:없음  [1732] 보낸이:정현호  (비주얼씨)  2000-07-18 20:53  조회:360*////////////////////////////////////////////////////////////////////////////// 제 글들은 절대로 상업적 목적으로 사용될수 없으며, 저자인 저의 허락없    //// 이는 그 어느곳에도 게시를 할 수 없습니다.                               //////////////////////////////////////////////////////////////////////////////*기타 궁금한 사항은 아래로 문의를 바랍니다.ashulam@hitel.netashulam@isoft.co.kr* 지난 시간에는 윈도우 소켓 초기화를 서버 프로그램(?)을 예로 들어 설명을 했었습니다. 이번 시간에는 클라이언트 프로그램에 대한 이야기를 하려합니다. 서버 프로그램과 그다지 다를점은 없습니다. 서버에서 listen함수로 접속을 기다렸던 부분을 클라이언트에서는 connect함수로 접속을 하는 부분이 달라질뿐입니다. 따라서 이번 게시물에서는 그렇게 많이 다룰 내용은 없을듯합니다. 거의다 지난 시간에 사용했던 함수들과 다를바가 없거든요. ^^; 지난 게시물을 잘 읽으신 분들은 큰 무리없이 이번 게시물은 그냥 읽고 넘어가는 정도일겁니다.[예제코드 프로젝트 구성및 사용법] 이 게시물에 관한 예제는 Network\TCP\Client에 있습니다. 프로젝트에 ws2_32.lib wsock32.lib 파일을 재정의 하셔야합니다. 사용법] Client 서버프로그램의IP주소 서버프로그램의포트번호(2000-65535증 아무거나) 서버의 IP주소와 포트번호는 지난게시물에서 서버프로그램에서 사용했던 인자인IP와 포트번호와 같은 값을 입력하면됩니다. 만일 자신의 IP가 111.222.111.222라면? server 111.222.111.222 5001 client 111.222.111.222 5001[윈도우 소켓을 이용한 네트웍 프로그래밍]*[클라이언트 프로그램의 구조와 서버 프로그램의 구조는 어떻게 다를까?][클라이언트 프로그램의 구조와 서버 프로그램의 구조는 어떻게 다를까?]아래의 예가 정확한 예라고 말할수는 없습니다만, 클라이언트/서버( 이하 : C/S )의 대표적인(?) 예라고 할수 있습니다. 대표적인 예 맞나? -_-;[서버]                               [클라이언트]WSAStartup();                    WSAStartup();socket();                        socket();bind();                          bind();listen();                        accept();                        connect();send() / recv()                  send()/recv();                                 closesocket();                   closesocket();WSACleanup();                    WSACleanup();지난 시간에 다룬 서버와 클라이언트는 크게 다를게 없습니다. 서버의 listen,listen대신 클라이언트에는 connet가 있을뿐입니다. 다시 한 번 강조 하지만 달라진 점은 거의 없습니다.[connect()]int connect ( SOCKET s, const struct sockaddr FAR*  name, int namelen );s : 설정한 소켓입니다.name : 연결할 서버의 주소에 대한 정보를 넣은 구조체입니다. ^^;namelen : sockaddr인자의 크기를 넣으면 됩니다.리턴값 : 성공적으로 연결이 될 경우 0이 리턴됩니다.실제 코드를 나열해 보도록 하죠.//클라이언트 프로그램의 구조를 봐요.-----------------------------------------#include <stdio.h>#include <windows.h>void main(){    WSADATA        wsaData;    SOCKET         Socket;        //소켓을 선언합니다.    SOCKADDR_IN    ServerAddress; //소켓의 주소 정보를 넣는 구조체입니다.    unsigned short Port = 5001;   //포트 번호.    int            ReturnVal;       //윈도우 소켓을위한 초기화....    if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR)    {        printf( "WSAStartup설정에서 문제 발생.\n" );        WSACleanup();        exit( 0 );    }    //서버와의 연결을 위한 소켓을 만듭니다.    Socket = socket(AF_INET, SOCK_STREAM,0); //    if( Socket == INVALID_SOCKET ) //에러 발생시 문구 출력.    {        printf( "소켓을 생성할수 없습니다." );        WSACleanup();        exit( 0 );    }    //반드시 AF_INET이어야합니다.    ServerAddress.sin_family = AF_INET;               //IP주소값. INADDR_ANY는 아무거나입니다. ^^;        ServerAddress.sin_addr.s_addr = inet_addr( "210.106.224.142" );     ServerAddress.sin_port = htons( Port );  //포트번호    //지정한 서버로 연결을 해 본다.    ReturnVal = connect( Socket, (struct sockaddr*)&ServerAddress,                 sizeof(ServerAddress) );    //ReturnVal이 0이 아니면, 문제가 있는 경우입니다.    if( ReturnVal )    {        printf( "서버로 연결을 할 수 없습니다.\n" );        closesocket( Socket );        WSACleanup();        exit( 0 );    }    else    {        printf( "서버 접속이 성공했습니다.\n" );    }    closesocket( Socket ); //소켓을 닫습니다.    WSACleanup();    printf( "클라이언트 프로그램이 종료 되었습니다.\n" );    getchar();}//클라이언트 프로그램의 구조를 봐요.-----------------------------------------앞 서버 프로그램과 달라진 부분만 집중적으로 보시면 좋을 듯합니다.이상으로 기본적인 클라이언트와 서버의 접속을 마칩니다. 다음 게시물부터는 실제로 네트웍상에서 데이터를 보내보죠. ^^;『시지프스(Cezips) C/C++프로그래밍-MS-WINDOWS 강의란 (go CEZIPS)』 128번 제  목:[강좌] WinSock을 이용한 네트웍 프로그래밍 05                 올린이:불의악마(조재영  )    00/09/05 16:04    읽음:252 관련자료 없음 ----------------------------------------------------------------------------- 제  목:[강좌] WinSock을 이용한 네트웍 프로그래밍 #05   관련자료:없음  [1733] 보낸이:정현호  (비주얼씨)  2000-07-18 20:53  조회:343*////////////////////////////////////////////////////////////////////////////// 제 글들은 절대로 상업적 목적으로 사용될수 없으며, 저자인 저의 허락없    //// 이는 그 어느곳에도 게시를 할 수 없습니다.                               //////////////////////////////////////////////////////////////////////////////*기타 궁금한 사항은 아래로 문의를 바랍니다.ashulam@hitel.netashulam@isoft.co.kr* 이번장은 윈도우 소켓과는 전혀 관련이 없는 부분입니다만, 꼭 알아 두셔야 할 부분입니다. 바로 쓰레드죠. 이미 쓰레드를 아시는 분이라면 가볍게 넘기시면 될테고 모르시는 분은 잘 숙지해 두셔야 할겁니다. 쓰레드를 알기에 가장 좋은 방법은 운영체제에 관한 책을 공부해 보시는것입니다만, 시간이 않되시는 분은 부득이하게아래의 글이라도 읽어두시면 작게나마 도움이 될겁니다. ^^;[예제코드 프로젝트 구성및 사용법] 이글과 관련된 예제는 Network\Thread에 있습니다. 프로젝트를 특별히 수정할 필요도 없으며 특별한 인자도 없습니다.[윈도우 소켓을 이용한 네트웍 프로그래밍]*쓰레드란?*쓰레드를 만들기.*쓰레드를 사용한 서버의 접속 처리 부분.5. 쓰레드( Thread ) 지금까지는 여러분과 본 내용은 단지, 특정한 IP와 포트를 가진 서버로 접속을 하고 연결을 끊는것이 전부였습니다. 이번장에서는 원래 데이터 송수신으로 바로 들어가려고 했습니다만, 큐 만들기나 윈속 이벤트 처리도 있고해서 쓰레드를 간단히 짚고 넘어가보겠습니다. 진짜 서버를 제대로 만들려면 이 쓰레드 관리가 생명입니다만, 제 글의 목적은 어디까지나 윈속입니다. 쓰레드를 깊게 다룰수는 없고 윈속을 사용하는데 문제가 없을 정도로만 보겠습니다. 쓰레드는 여러분께서 직접 공부를 해 두시는게 좋습니다.*쓰레드란? 쓰레드를 보기전에 함수 호출과정을 보도록 하죠. ^^; void main() {    Function_1();    Function_2();     .     .    Fucntion_N(); } 위의 예를 보면 Function1~N까지의 함수들이 실행된다는 사실은 분석(?)하지 않아도 누구나 다 아실겁니다. 그 과정도 다 아시겠지만, 한 번 설명하자면...... main함수는 프로그램의 제어권을 Fucntion_1으로 넘기고 Function1은 자신의 내용을 실행합니다. 전부 실행하고 나면 제어권은 다시 main함수로 돌아오게 됩니다. 다음 중에 바로 보이는 Function_2로 main함수는 다시 제어권을 넘기고 Function_2함수가 실행되고 제어권은 다시 main으로 돌아오게 됩니다. 그 과정이 Function_N 까지 계속되고 main함수는 종료되게 됩니다. 그럼 쓰레드는 뭐냐? 바로 그걸 설명하기 위해 위의 과정을 설명한 겁니다. 우선은 쓰레드도 하나의 함수라고 생각하십시요. 그리고 아래의 과정을 보도록 하죠. void main() {    Thread_1();    Thread_2();     .     .    Thread_N(); } 위와같이 쓰레드가 N개 있습니다. main함수가 실행되면, 당연히 프로그램의 제어권은 main이 가지게 됩니다. 다음 Thread_1을 호출하면, 프로그램의 제어권이 Thread_1으로 넘어가는것이 아니라 제어권은 main에 그대로 남아있고, 독립적인 제어권을 가진 하나의 함수를 호출하고 main함수내의 제어권은 그대로 유지된다고 보시면됩니다. 즉, 함수와같이 하나의 흐름을 가지고 갔다왔다하는 구조가 아니라 자신의제어권은 계속 인정되고 프로그램을 진행하면서 쓰레드를 호출하면 함수들이 살아있는 상태로 계속 유지되는 겁니다. 위와 같은 경우는 N개의 함수들이 프로그램이 종료될때까지 계속 살아있다고 보시면 됩니다. 도스때 프로그램을 해 보신분이면, 램상주 프로그램을 생각하시면 좋겠고요. 윈도우 API프로그램을 해 보신분들은 윈도우 프로시져를 생각해 주시면 이해가 조금은 쉽게 되지 않을까 싶습니다. 하지만, 위의 말 몇마디로 쓰레드를 처음 접하시는 분들께서 쉽게 이해하지는 못하실겁니다. 앞으로 나올 코드를 보며 이해를 하시고, 윈도우 관련책에 짧게 나온 쓰레드에 관한 지식이라도 지속적으로 보다보면 이해를 하실수 있을겁니다. ^^; 그리고보니 Hitel GMA 강좌란에도 쓰레드에 관한 간단한 예가 있으니 참조하시면 도움이 될겁니다. ^^;*쓰레드를 만들기. 앞에서도 이야기했지만, 쓰레드는 호출하면 프로그램 흐름에 영향을 미치지 않고 계속 살아있는 함수라고 정의했었습니다. 왜 제가 함수라고 정의 했는지는 아래에 기술될 쓰레드의 모양을 보면 아실겁니다. 우선은 형태만 보십시요.사용 컴파일러 : VC++ 6.0컴파일 옵션 : Alt+F7을 누른후 프로퍼티 시트중 C/C++을 고른후 Category 항목 콤              보박스를 드랍다운 시킨후 Code Generate를 선택합니다.              Use run-time library의 항목 중 MultiThread라는 단어가 들어가는              항목중 아무거나 선택합니다. 참고로 MultiThreaded를 선택했습니다//쓰레드 구동 프로그램-------------------------------------------------------#include <stdio.h>#include <process.h>#include <windows.h>unsigned long __stdcall Thread( void *arg ){    while( 1 )    {        printf( "in Thread!!\n" );        Sleep( 100 );    }    return 1;}void main(){    unsigned long TempValL;    //프로그램이 종료될때까지 0.1초 간격으로 in Thread라는 문자열을 출력합니     //다.    CreateThread( NULL, 0, Thread, 0, 0, &TempValL );    //쓰레드를 구동한후 제어권이 메인 함수로 돌아왔으면, 아래의 구문이 동작합    //니다. 즉, 아래의 문구가 나오면 현재 프로그램이 Thread()안에 머물고 있지    //않음을 알 수 있습니다.    printf( "In Main.\n" );    //아무키나 누르면 종료합니다.    getchar();}//쓰레드 구동 프로그램======================================================= 처음 보시는 함수들을 보겠습니다.HANDLE CreateThread(  LPSECURITY_ATTRIBUTES lpThreadAttributes, // 보안 속성  DWORD dwStackSize,                        // 스택 크기  LPTHREAD_START_ROUTINE lpStartAddress,    // 쓰레드 함수의 포인터  LPVOID lpParameter,                       // 쓰레드에 들어갈 인자  DWORD dwCreationFlags,                    // 쓰레드 생성시 옵션.  LPDWORD lpThreadId                        // 쓰레드 ID에 대한 포인터.);lpThreadAttributes : 쓰레드 핸들에 대한 상속이나 특성을 결정짓는 옵션이라고                       하는데 전 NULL을 애용하죠. ^^;dwStackSize        : 쓰레드에 할당될 스택의 크기. 0인 음수면 디폴트값을 설정                     해주는데, 불려진 쓰레드와 같은 크기를 잡습니다.lpStartAddress     : 쓰레드의 주소lpParameter        : 쓰레드의 인자값 위의 예중에서는                     unsigned long __stdcall Thread( void *arg )에                     void *arg인자로 넘어갈 값입니다.dwCreationFlags    : 생성시 바로 생성될것인지 특정한 옵션에 의해 생성될 것인                     지를 결정합니다.lpThreadId         : 쓰레드 ID에 대한 포인터.리턴값             : 쓰레드에 대한 핸들이 리턴됩니다. 쓰레드 생성 실패시엔                      NULL이 리턴됩니다. 저도 쓰레드를 깊게 사용해 보지 못해 위에 설명한 내용 모두를 사용하지 못하고 전부 알지도 못합니다. 대부분의 경우 디폴트 설정으로 사용합니다. ^^; 쓰레드를 만드는 방법은 CreateThread말고도 _begintherad, _beginthreadex가 있습니다. _beginthreadex는 NT(Win2000)환경에서만 작동합니다. 저도 처음에 _beginthreadex 사용했다가 물 많이 먹었었습니다. 윈98에서는 않돌아간다고.... ^^;*쓰레드를 없애기. 별로 추천하지는 않는 방법이지만, TerminateThread함수입니다. 그 사용법은 아래와 같습니다. 쓰레드를 만들고 얻은 핸들을 이용해서 쓰레드를 없애는 방법이죠.HANDLE hThread;hThread = CreateThread( NULL, 0, Thread, 0, 0, &TempValL );...TerminateThread( hThread, 0 ); //Thread라는 쓰레드를 없앤다.*BOOL TerminateThread( HANDLE hThread, DWORD dwExitCode );HANDLE hThread : 쓰레드의 핸들.DWORD dwExitCode : 쓰레드 종료시 리턴될 값.리턴값 : 성공시엔 0이 아닌값이 리턴됩니다. 가장 안정적인 방법은 쓰레드도 내부의 조건이 맞지 않을 경우 종료 시키주는 경우입니다. 위의 예를 보면, while( 1 )이라는 무지막지한 루프안에서 갇혀 헤어나지 못하고 있습니다만, 쓰레드만을 위한 전역 변수를 만들어 쓰레드를 외부에서 꺼주는 방법이 좋습니다. TerminateThread가 왜 않좋으냐? 그 이유는 바로 강제성에 있습니다. 위의 예는 간단히 문자열을 화면에 출력하는게 고작이라 별문제가 되지 않습니다. 하지만 쓰레드안에서 몇십메가 혹은 그 이상의 메모리를 할당하고 해제하지 않은 상태에서 강제로 종료했다고 생각해 보십시요. 메모리 새는건 불 보듯 뻔합니다. 혹은 일정한 처리과정을 거치지 않고 중간에 엉뚱한 값을 가진후 결과값을 리턴한다면 올바른 처리가 되지 않겠죠? 하지만, 위와같이 그 내용이 중간에 강제로 종료해도 별 문제가 되지 않는 상황이라는 점을 확실히 알고 계신다면, 얼마든지 사용해도 좋습니다. 항상 나쁘다는 것은 아닙니다. ^^;*쓰레드를 사용한 서버의 접속 처리 부분. 그럼 이제 까지 왜 쓰레드 사용법에 대해서 배웠는지 어디에 쓰레드를 쓸지를 이제 밝혀야 될 때가 온 듯 하군요. ^^; 쓰레드를 사용한 이유는 바로 윈도우 소켓을 좀 더 깔끔하게 사용하기 위함과 윈속에 있는 블럭킹모드(무한정 기다리는)로 작동하는 함수 때문입니다. 첫째 깔금한 사용이란 쓰레드로 윈도우 소켓에 들어오는 메시지를 잡아내서 사용하기 위함입니다. 쓰레드 안에 접속요청/접속끊김/데이터 받기등의 기능을 모두 모아 넣고 그 메시지에 따라 처리를 해주는 겁니다. 윈도우 프로그램에서 프로시져안에 키입력이나 마우스 움직임같은 부분에 대한 처리를 넣어 두는것 처럼요. 윈도우프로그램에서 프로시져는 처리해야할 메시지가 너무 많기 때문에 난잡해 지는 단점이 있었습니다만, 윈도우 소켓으로 넘어오는 메시지는 많지 않기 때문에 이 방법이아주 효율적입니다. 둘째는 블럭킹 함수들 때문이죠. 서버 프로그램이 실행되고 해야 할 일이 한둘이 아닌데, accept()함수 하나 실행되면, 연결이 오기전까지는 바로 멈춰 버립니다. 접속에 관한 부분을 외부로 빼 버리면, 즉 쓰레드에 넣고 서버가 해야할 일을 하며접속이 들어오면 쓰레드에서 처리를 해 버리는거죠. 아래에 바로 그 예를 들겠습니다.[지금까지의 방식]                [쓰레드 사용]void main()                      unsigned long Thread( void *arg ){                                { WSAStartUp()                        while( 1 ) socket();                           { bind()                                 accept(); listen()                               접속에 대한 처리;                                     } accept() //무작정 기다림.        } closesocket();                   void main() WSACleanup();                    {}                                    WSAStartUp();                                     socket();                                     bind();                                     listend();                                                                          Createthread( Thread );                                                                          서버에 관련된 프로그램을 진행.                                   } 지금은 쓰레드안에 접속에 관한 부분만 있기 때문에 쓸모 없어 보일지도 모릅니다만, 저 쓰레드안에 소켓이 닫힐때, 데이터가 왔을때등에 대한 처리까지 넣어두면 상황이 달라지겠죠? ^^; 바로 다음 게시물에서 다룰 내용입니다. 다음 시간엔 쓰레드 안에 들어갈 내용들을 좀 더 구체적으로 보겠습니다.『시지프스(Cezips) C/C++프로그래밍-MS-WINDOWS 강의란 (go CEZIPS)』 129번 제  목:[강좌] WinSock을 이용한 네트웍 프로그래밍 06                 올린이:불의악마(조재영  )    00/09/05 16:04    읽음:261 관련자료 없음 ----------------------------------------------------------------------------- 제  목:[강좌] WinSock을 이용한 네트웍 프로그래밍 #06   관련자료:없음  [1734] 보낸이:정현호  (비주얼씨)  2000-07-18 20:53  조회:330*////////////////////////////////////////////////////////////////////////////// 제 글들은 절대로 상업적 목적으로 사용될수 없으며, 저자인 저의 허락없    //// 이는 그 어느곳에도 게시를 할 수 없습니다.                               //////////////////////////////////////////////////////////////////////////////*기타 궁금한 사항은 아래로 문의를 바랍니다.ashulam@hitel.netashulam@isoft.co.kr* 지금까지는 클라이언트/서버의 초기화및 연결까지를 다루었습니다. 이제 실제로 연결될 두 프로그램 사이에 실제로 데이터를 보내도록하죠. 간단히 send/recv만알면 되긴 합니다만, 그렇게 간단하지만은 않습니다. ^^; 이번 장에서는 간단히 send/recv가 어떻게 쓰이는지만을 봅니다. 코드의 일부를 뜯어 놓은듯한 즉, 단편적인 느낌이 들긴합니다만, 실제로 채팅 클라이언트/서버 프로그램을 만드는 마지막 글에서 모든 부분을 알게 될것입니다. 그러니 너무 조급하게 생각하지 마시고이번 글은 send/recv시에 패킷이 짤려서 올때 어떻게 처리를 하는지와 send가 불가능한 상황일때는 어떻게 처리를 하는지정도에 관심을 두고 보심이 좋을듯합니다.아직은 네트웍 프로그램을 위한 단편적인 지식을 쌓는 단계일 뿐이라는 점을 항상잊지 말아 주십시요. ^^;[윈도우 소켓을 이용한 네트웍 프로그래밍]*[이벤트 메시지를 받아봐요~]*[send()/recv()와 큐]6. 윈도우 소켓을 이용한 데이터 송수신.[이벤트 메시지를 받아