이 단원 전에 2장으로 걸쳐서 주소에 대해 설명을 했습니다.
먼저 bind의 함수에 대해 알아보았고 바로 전단원 에서는 bind 함수를 사용하기 위한 네트웍바이트순서와 IP, port에 대해서 다루었습니다. 이제 여러분은 전화통신 상으로 비교를 해보면 자신의 전화기에 번호를 부여할 수 있는 함수를 다룰 수 있게 된것입니다.
이번 장에서는 bind를 사용한 프로그램을 직접 만들어보면서 그동안 배웠떤 네트웍 관련 함수들을 모두 사용해 봄으로써 어떻게 쓰이는지 확실히 짚고 넘어가보자 합니다. 프로그램이 어떤 흐름으로 돌아가는지를 잘 파악하는게 중요하다고 말씀드리고 싶네요.
먼저 윈속관련 함수를 사용하기 위해선 윈속관련 dll을 초기화 해야 한다고 했습니다. 이를 초기화 하는 이유는 '앞으로 윈속관련 함수들을 호출할테니 잘 봐달라' 라고 말하는 것과 같습니다. 이를 위해 필요한 함수는 WSAStartup 함수입니다. 맨 첫장에서 설명 드렸죠? 그리고 윈속관련 함수 호출을 끝낼때는 WSACleanup 함수를 호출해야 한다고 했습니다. 물론 이 함수를 호출하지 않아도 내부적으로 운영체제가 알아서 처리해주지만 우리는 정석대로 갑니다. 참고로 윈속관련 함수를 사용하기 위해선 반드시 'ws2_32.lib' 파일을 링크해 주어야 합니다.
( Alt + F7 -> Link탭으로 이동 -> ws2_32.lib 파일 추가 )
그리고 필요한게 서로 통신(데이터를 주고받는 행동)을 하기위해 필요한게 한가지 있었죠? 바로 '소켓'입니다. 소켓을 먼저 생성한다음 이 소켓으로 클라이언트들과 통신을 하게 된다고 했죠. 소켓을 생성하기 위한 함수는 socket 함수 입니다. 잊어버리지 않으셨죠?
그다음이 우리가 바로 전까지 배웠던 bind 함수입니다. 집에 전화기를 들여놓으면 그냥 전화가 걸려오지는 않습니다. 바로 번호란게 있어야 다른 사람들(클라이언트)이 전화를 걸어오는(접속요청)것이죠. 이를 위한 함수가 bind입니다. 서버의 주소정보를 할당해서 클라이언트가 이 주소정보대로 접속할 수 있도록 하는 기능을 수행하는 함수입니다.
자 여기까지 입니다. 이 순서대로 프로그램을 직접 짜보았습니다. 흐름을 잘 읽어 보세요.
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
/* 윈속관련 함수가 에러날땐 항상 이 함수를 호출할것임 */
void ErrorHandling( char *message )
{
fputs( message, stderr );
exit( 1 );
}
/* 프로그램의 시작점인 main함수 */
void main( void )
{
/* 데이터 선언 부분 */
WSADATA wsaData;
SOCKET servSocket;
struct sockaddr_in servAddr;
int result;
/* 윈속 초기화 ( 윈속함수 사용을 선언함 ) */
if ( WSAStartup( MAKEWORD( 2, 2 ), &wsaData ) != 0 )
ErrorHandling( "WSAStartup failed with %d\n", WSAGetLastError() );
/* TCP 소켓을 생성 */
servSocket = socket( PF_INET, SOCK_STREAM, 0 );
if ( servSocket == INVALID_SOCKET )
ErrorHandling( "Create socket failed with %d\n", WSAGetLastError() );
/* 주소정보 데이터를 초기화 */
servAddr.sin_family = AF_INET; /* 인터넷 프로토콜(IPv4) 사용 */
servAddr.sin_addr.s_addr = htonl( INADDR_ANY );/* 네트웍바이트오더로 넣어줌 */
servAddr.sin_port = htons( 7777 ); /* 네트웍바이트오더로 포트번호 초기화 */
/* 주소를 할당( bind 함수 사용 ) */
if ( bind( servSocket, ( struct sockaddr* )&servAddr, sizeof( servAddr ) )
== SOCKET_ERROR )
ErrorHandling( "bind failed with %d\n", WSAGetLastError() );
/* 메시지 출력 */
printf( "Binded server socket! \n" );
/* 소켓을 제거 */
closesocket( servSocket );
WSACleanup();
}
어때요? 너무 시시하죠? 사실 이 프로그램은 어느 클라이언트의 접속도 받을 수 없는 프로그램입니다. 정작 클라이언트의 접속을 수락하는 함수는 없지요. 아직 배우지 않았으니 넣지 않았습니다. 이 프로그램이 하는 일은 한마디로 말해서 '집에 전화기를 설치하고 번호만 할당' 하는 프로그램 입니다. 전화를 받거나 울리게 하는 그런 기능은 전혀 없는 프로그램이죠.
하지만 이 과정은 서버프로그램에서 굉장히 중요한 부분이니 꼭 이해하고 넘어가셔야 합니다. 그리고 위해서 INADDR_ANY 라는 플래그가 나왔는데 이 플래그는 winsock2 헤더파일에 정의되어 있는 일반 상수값입니다. 이 플래그가 담고 있는 의미는 사용가능한 아이피를 하나 골라서 대입한다 라는 의미를 담고 있습니다. 이해가 잘 되지 않으시면 그냥 지금 사용하고 있는 아이피를 몰라도 INADDR_ANY 플래그를 넣어주면 그대로 사용할 수 있게 한다고만 알아두세요. 만약 이 플래그가 존재하지 않는다면 아이피가 바뀔때마다 컴파일을 다시 해줘야 겠지요.. 물론 다른방법으로도 해결 가능하겠지만 말예요( 웃음 )
그런데 한가지 주의할점이 있습니다. 전에 아이피를 sockaddr_in 구조체에 대입하기 위해서는 inet_addr 함수를 써야한다고 설명드렸죠? 그렇지만 INADDR_ANY라는 플래그를 사용할 경우에는 htonl 함수를 사용한다는 점 잊지 마세요.
지금까지 컴파일러가 실행되어 있지 않습니까? 그렇다면 지금 당장 실행해서 직접 코드 적고 컴파일 해보세요. 눈으로 보는건 금방 잊어버리게 됩니다. 하지만 손에 익으면 오래오래 남게 되죠^^
- Reference
'[ Windows Program ] > Windows API' 카테고리의 다른 글
클라이언트의 연결을 처리하는 accept 함수 (2) | 2011.03.07 |
---|---|
클라이언트의 접속을 가능하게 하는 listen 함수 (0) | 2011.03.07 |
주소 사용법( 주소체계, 바이트순서 ) (0) | 2011.03.07 |
주소 할당 함수 bind (0) | 2011.03.07 |
소켓 프로그래밍 흐름도(클라이언트) (0) | 2011.03.07 |