1. 소켓의 개념과 생성, 프로토콜의 설정

MFC 소켓 클래스에 들어가기 전에 윈속 소켓 프로그래밍에 대해 간략하게 정리 해보겠습니다.

1.1 소켓의 개념
   네트워크를 이용한 통신은 전화망을 이용한 통신과 그다지 다르지 않습니다. 전화망을 이용한 통신에서 전화기는 사람과 사람을 이어주는 역할을 하는데요. 이를 일종의 소켓이라고  할 수 있겠습니다.
  단도직입적으로 말하면, 소켓이란 떨어져 있는 두 개체를 연결해 주는 일종의 도구라고 할 수 있겠네요.
1.2 소켓 구현
1.2.1 윈속(Winsock) 초기화 하기
  윈속 프로그래밍시에는 반드시 윈속 초기화를 해야 합니다. 이는 프로그램에서 사용하는 윈속버전을 표시함으로써 이 버전의 윈속 사용을 위한 라이브러리 초기화 작업을 위함 입니다.

#include <winsock2.h>

int WSAStartup(
WORD wVersionRequested,
LPWSADATA lpWSAData
);

  
  첫번째 파라미터에는 프로그램에서 사용하는 윈속의 버전을 WORD 형으로 변환한 값이 들어갑니다. 상위 8비트에는 부버전을 하위 8비트에는 주버전을 표시합니다. 예를 들어 2.2 버전을 사용한다면 이 파라미터에는 0x0202를 사용하고 3.2 버전을 사용한다면 0x0203을 사용하게 되는 것 입니다. 이를 편리하게 변환하기 위해 MAKEWORD 함수(매크로 함수)를 사용하는 것이 일반적이에요.

  두번째 파라미터에는 WSADATA 타입 변수의 포인터가 들어갑니다. 함수 호출이 성공적으로 이루어지면 이 변수에는 로딩한 DLL의 정보가 채워지게 됩니다.

프로그램 종료시에는 WSADATA를 해제해 주어야 하는데요. 이때 사용하는 함수가 WSACleanup 함수 입니다.

int WSACleanup(void); // 성공시 0, 실패시 SOCKET_ERROR 리턴

1.2.2 소켓 생성
 소켓 생성이란 전화망을 이용한 통신에 비유해 볼때 전화기를 마련하는 것과 같습니다.

SOCKET socket(int af, int type, int protocol); // 성공시 소켓 핸들, 실패시 INVALID_SOCKET 리턴

  첫번째 파라미터에는 주소의 계열을 표시합니다. 
       PF_INET : IP v4의 주소 체계
       PF_INET6 : IP v6의 주소 체계
       PF_LOCAL : Local 통신을 위한 유닉스 프로토콜
       PF_PACKET : Low level socket을 위한 인터페이스
       PF_IPX : IPX 노벨 프로토콜

  두번째 파라미터에는 소켓의 타입을 지정합니다.
       SOCK_STREAM : TCP프로토콜을 사용시
       SOCK_DGRAM :  UDP프로토콜을 사용시

  세번째 파라미터에는 이 소켓에서 데이터를 전송할때 사용할 프로토콜을 지정합니다.

       IPROTO_TCP : TCP 프로토콜 사용시
       IPROTO_UDP : UDP 프로토콜 사용시
  하지만 실제 프로그래밍시에는 보통 0을 써주는데, 0을 넣게 되면 주소체계와 타입을 보고 자동으로 설정하게 됩니다.

1.2.3 주소와 포트 할당 
  전화기만 있고 전화번호가 없다면 우리는 통화를 할 수 없겠죠. 전화기에 전화번호를 할당해주는 역할을 하는 함수가 바로 bind 함수 입니다.

int bind(SOCKET s, const struct sockaddr FAR *name, int namelen); // 성공시 0, 실패시 SOCKET_ERROR 리턴

  첫번째 파라미터에는 사용할 소켓의 객체가 들어갑니다.

  두번째 파라미터에는 서버의 주소가 들어가는데 이에 대해서는 다음 포스팅에 자세히 설명하도록 하겠습니다.

  세번째 파라미터에는 서버 주소의 길이가 들어갑니다.

1.2.4 연결 요청 대기(listen) 상태로 진입
  이제 서버에서는 클라이언트가 연결을 요청할 수 있는 상태로 만들어 줘야 하겠죠? 이 역할을 하는 함수가 listen 함수 입니다.

int listen(SOCKET s, int backlog); // 성공시 0, 실패시 SOCKET_ERROR 리턴

  첫번째 파라미터에는 사용할 소켓의 객체가 들어갑니다.

  두번째 파라미터에는 버퍼의 크기가 들어갑니다. 서버에 연결 신호가 동시에 많이 왔을 때는 특정 버퍼에 저장을 해두고 연결을 해 줘야 하는 경우가 생기게 되는데 소켓에 그 버퍼의 크기를 지정하는 부분이 되겠습니다.
1.2.5 연결 수락
  클라이언트가 서버에 연결 요청을 하면 이를 수락해 주는 부분입니다. 이 역할은 담당하는 함수가 바로 accept 함수 입니다.

SOCKET accept(SOCKET s,  struct sockaddr FAR *addr, int FAR *addrlen); // 성공시 소켓 핸들, 실패시 INVALID_SOCKET 리턴

  파라미터의 형태는 bind 함수와 동일하나 bind 함수는 서버의 주소를 사용하고 accept 함수는 클라이언트의 주소를 사용합니다.

1.2.6 클라이언트에서의 연결 요청
  클라이언트에서 서버로 연결 요청을 할 때는 connect 함수를 사용합니다.

int connect(SOCKET s, const struct sockaddr FAR *name, int namelen); // 성공시 0, 실패시 SOCKET_ERROR 리턴



1. sockaddr_in 구조체
  소켓을 사용하기 위해선 소켓에 서버의 IP와 Port를 바인딩 해주어야 합니다. 이 과정에서 IP와 Port를 저장하는 sockaddr_in 구조체를 보셨을 겁니다. sockaddr_in 구조체는 IPv4의 주소 체계를 저장할 수 있는 구조체 입니다.

struct sockaddr_in {
    sa_family_t       sin_family;    
   
// 주소의 계열 (이전 포스팅에서 나왔던 socket 생성 함수의 첫 인자 값과 동일)
    uint16_t             sin_port;        
   
// 16bit TCP / UDP Port
    struct in_addr    sin_addr;        
    
// 32bit IPv4 Address
    char                 sin_zero[9];    
    
// 사용하지 않습니다.
};
           - sockaddr_in 구조체의 원형-

struct in_addr(
    uint32_t        s_addr;
};
           - in_addr 구조체의 원형 -
2. Byte Order 변환
  네트워크 상에서는 Big-Endian 방식으로 데이터를 전송한다. sockaddr_in 구조체에 저장되는 값들은 모두 Big-   Endian 방식으로 저장되어야 합니다. byte order 변환 함수에는 다음과 같은 것이 있습니다.

- htons : host byte order를 short 형의 network byte order로 변환
- ntohs : network byte order를 short 형의 host byte order로 변환
- htonl : host byte order를 long 형의 network byte order로 변환
- ntohl : network byte order를 long 형의 host byte order로 변환

 

3. 주소 문자열을 Big-Endian 32bit 값으로 변환
주소 문자열을 Big-Endian 32bit 값으로 변환하기 위해서 inet_addr() 함수를 사용합니다.

unsigned long inet_addr(const char *string);
                 - inet_addr 함수의 원형 -

INI 파일의 구조는 보통 다음과 같이 되어있습니다.

예) setup.ini

 [Title1]
Name=test.cpp
Path=C:\temp\test.cpp
Version=2.1.0.1
[Title2]
Name=test.cpp
Path=C:\temp\test.cpp
Version=2.1.0.1
.
.

위 파일을 제어(읽기/쓰기)하려면 다음과 같은 함수를 사용합니다.

GetPrivateProfileString() : 파일에서 정보(문자열)를 읽어온다.
WritePrivateProfileString() : 파일에 정보(문자열)를 쓴다. 만약에 해당 섹션과 키값이 없으면 자동으로 생성한다.

각 함수의 원형은 다음과 같습니다.


DWORD GetPrivateProfileString(
  LPCTSTR lpAppName,       // [Title1]과 같은 섹션(대제목)입니다.
  LPCTSTR lpKeyName,       // Name과 같은 키값(구성요소)입니다.
  LPCTSTR lpDefault,           // 섹션이름이나 키이름을 찾지 못하면 디폴트로 출력할 스트링입니다.
  LPTSTR lpReturnedString// Name과 같은 키값(구성요소)에서 가리키는 값(test.cpp)을 저장할 버퍼입니다.
  DWORD nSize,                  // 키값을 저장할 버퍼의 사이즈입니다.
  LPCTSTR lpFileName        // INI 파일(setup.ini)의 경로입니다.
);
 BOOL WritePrivateProfileString(
  LPCTSTR lpAppName,     // [Title1]과 같은 섹션(대제목)입니다.
  LPCTSTR lpKeyName,     // Name과 같은 키값(구성요소)입니다.
  LPCTSTR lpString,           // Name과 같은 키값(구성요소)에 작성할 정보(문자열)입니다.
  LPCTSTR lpFileName      // INI 파일(setup.ini)의 경로입니다.
);


사용법은 각 함수의 파라메터에 맞게 값을 넣어주면 됩니다.

예를 들면..

GetPrivateProfileString( "Title1", "Name", "No Info", inbuffer, sizeof(inbuffer), "C:\\temp\\setup.ini" );
//설명 : C:\\temp\\setup.ini 파일에서 Title1의 Name 값을 inbuffer 사이즈만큼 읽어와라,
         Name값이 없으면 No Info값을 inbuffer에 저장하라.

WritePrivateProfileString( "Title1", "Name", outbuffer, "C:\\temp\\setup.ini" );
//설명 : C:\\temp\\setup.ini 파일에서 Title1의 Name 값을 outbuffer에 정보(문자열)를 써라.

 

APS
리소스 파일에 대한 바이너리 파일. 리소스 파일을 로딩하는데 사용한다.(로딩  속도 향상)

BSC
소스 브라우저 정보 파일(Browser database file). 이 파일은 BSCMAKER.EXE를 실행할 때 SBR 파일로부터 생성된다.

C
C언어 소스 파일. C 방식으로 컴파일된다. 만약 소스 내에 C++ 코드가 있다면 확장자를 CPP로 변경하거나 컴파일시 옵션을 /TP로 설정한다.

CLW(CLassWizard status file)
클래스 위저드 상태 파일. 프로젝트에 사용된 파일과 클래스에 관한 정보를 담고 있다. 클래스위저드를 사용하여 추가되는 메시지 핸들링 함수 등과 관련된 정보들이 포함된다.

CPP, CXX
C++ 언어 소스 파일. C++방식으로 컴파일된다.만약 확장자만 CPP이고 실제 내용이 C 코드이면 확장자를 C로 변경하거나 컴파일시 옵션을 /Tc로 설정한다.

DEF(Module Definition File)
모듈 정의 파일. 프로젝트 유형에 따라 사용 목적이 다른데 윈도우즈 또는 윈도우즈 NT 기반의 프로그램인 경우 익스포트되는 함수의 리스트, 힙(Heap) 크기, 세그먼트 속성 등을 지정한다.

DSP(Microsoft Developer Studio Project File)
프로젝트 정보를 포함하고 있는 파일. 단일 프로젝트 또는 서브 프로젝트를 build하기 위해 사용된다. 다른 사용자가 이 파일을 공유할 수 있지만 지역적으로(locally) makefiles을 익스포트해야 한다.

DSW(Developer Studio Workspace file)
Developer Studio의 환경 정보 파일. 워크스페이스 내의 각 프로젝트에 대한 엔트리 정보를 포함한 파일이다.

EXP(EXPort file)
익스포트되는 힘수와 데이터 정보를 포함한다.

H, HPP, HXX
헤더 파일. 이 파일은 함수의 원형 선언, 클래스 정의, 상수 정의를 위해 사용된다.

HPJ(context-sensitive Help ProJect file)
문맥 감지형 도움말 파일. AppWizard 단계 4 에서 [Context-sensitive help]를 체크하면 자동 생성된다.

INL(INLine function file)
인라인 함수 파일. 이 파일에는 인라인 함수가 정의된다.

MAP(MAP file)
프로그램의 엔트리 포인트, 심볼 이름, 시작 주소, 프로그램에 링크된 정보를 포함한다.

MDP(Microsoft DeveloPer studio file)
VC++ 2.X 버전에서 사용한 VCP 파일을 대체한다.

NCB(Parser information file)
클래스뷰와 컴포넌트 갤러리를 지원하기 위한 정보를 포함한다.

OPT
워크스페이스 환경 설정

PCH(PreCompiled Header file)
컴파일 속도를 향상 시키며 컴파일 옵션 /Yc, /Yu 또는 /YX를 사용할 때 생성된다.

PDB(Program DataBase file)
디버깅 정보 포함. 이 바이너리 파일은 컴파일링, 링킹 과정을 통해 얻어지는 디버깅 정보를 포함한다.

PLG(Program build LoG file)
빌드 로그 파일

RC, RC2(ResourCe source file)
프로그램에서 사용하는 리소스가 정의된 파일. 리소스 컴파일러(RC.EXE)에 의해 컴파일된다. 다이얼로그, 아이콘, 메뉴, 커서 등과 같은 리소스에 대한 정보가 기술되어 있다. RC2 또한 리소스에 대한 정보가 포함된다.

RCT(ResourCe Template file)
리소스 템플릿 파일

RES(RESource compiled file)
리소스 파일(RC)이 컴파일된 바이너리 파일

SBR(Source BRowser file)
소스 브라우저 파일. 이 파일은 소스 파일에 대한 상세한 정보들이 포함된다.

VCP
Workspace information file(VC++ 2.X 버전 또는 이후 버전)은 통합 개발 환경이 종료될 때의 상태 정보를 포함한다.

WSP
Workspace information file(16비트 버전)은 통합 개발 환경이 종료될 때의 상태 정보를 포함한다.

+ Recent posts