가상함수


가상함수는 virtual 예약어를 앞에 붙여서 선언한 메서드를 말한다. 따라서 가상 함수라는 말은 메서드라는 말을 내포하여, 이 가상 함수는 기본적으로 '자기 부정'을 전제로 작동한다. 달리 말해 파생 형식 에서 메서드를 재정의하면 가거의 정의가 완전히 무시된다는 특징이 있다. java와 비교하자면 자식클래스에서의 부모클래스의 함수를 오버라이드 하는 개념으로 이해했다. 하지만 재정의 이후에 호출하는 과정에서는 자바와는 조금 다른 방식을 취한다.


가상함수는 다음과 같이 선언한다.

virtual void PrintData();


// #include "stdafx.h" #include

using namespace std; class CMyData { public: virtual void PrintData() { cout << "CMyData: " << m_nData << endl; } void TestFunc() { cout << "***TestFunc()***" << endl; PrintData(); cout << "****************" << endl; } protected: int m_nData = 10; }; class CMyDataEx : public CMyData { public: virtual void PrintData() { cout << "CMyDataEx: " << m_nData * 2 << endl; } }; int main() { CMyDataEx a; a.PrintData(); CMyData &b = a; b.PrintData(); a.TestFunc(); }


위의 예제에서 CMyData::PrintData() 함수를 가상 함수로 선언했는데, 이 함수는 내부 멤버 데이터인 m_nData의 값을 출력한다. 그리고 32번 행에서 이 PrintData() 함수를 재정의했다. 여기까지는 기존의 일반 베서드를 재정의한 것과 크게 다르지 않기 때문에 호출하게 되면 CMyDataEx 클래스의 PrintData() 메서드를 호출한게 된다.



CMyData  &b = a;

b.PrintData();

재밌는 코드가 등장하게 되는데 실형식은 CMyDataEx이며 참조 형식은 기본 클래스인 CMyData에 속한 참조자 b가 선언됐다. 그리고 b를 통해 PrintData()를 호출했습니다. 일반 메서드의 경우 실 형식은 중요하지 않고 참조 형식이 무엇인지에 따라 어떤 메 서드가 호출되는지 결정이 났지만 가상함수는 다르다. 가상 함수는 일반 메서와 달리 참조 형식이 무엇이든 실 형식의 메서드를 호출한다.


"일반 메서드는 참조 형식을 따르고, 가상함수는 실 형식을 따른다.



	
void TestFunc()
{
		cout << "***TestFunc()***" << endl;

		PrintData();
		cout << "****************" << endl;
}


PrintData(); 는 누구를 호출할까? TestFunc() 함수는 기본 클래스인 CMyData의 멤버이다. 그러므로 위의 PrintData()는 기본적으로 CMyData 클래스의 PrintData() 함수를 말하는 것이다. 그런데 문제는 PrintData() 함수가 '가상 함수'라는 사실이다. 이렇게 되면 지금 PrintData() 함수는 '미래'에 재정의된 함수일 수 있다.

만일 파생형식(자식)에서 PrintData() 가상 함수를 재정의한다면 위의 PrintData()는 미래의 함수를 호출하는 것이다.


가상함수


가상함수는 virtual 예약어를 앞에 붙여서 선언한 메서드를 말한다. 따라서 가상 함수라는 말은 메서드라는 말을 내포하여, 이 가상 함수는 기본적으로 '자기 부정'을 전제로 작동한다. 달리 말해 파생 형식 에서 메서드를 재정의하면 가거의 정의가 완전히 무시된다는 특징이 있다. java와 비교하자면 자식클래스에서의 부모클래스의 함수를 오버라이드 하는 개념으로 이해했다. 하지만 재정의 이후에 호출하는 과정에서는 자바와는 조금 다른 방식을 취한다.


가상함수는 다음과 같이 선언한다.

virtual void PrintData();


// #include "stdafx.h" #include

using namespace std; class CMyData { public: virtual void PrintData() { cout << "CMyData: " << m_nData << endl; } void TestFunc() { cout << "***TestFunc()***" << endl; PrintData(); cout << "****************" << endl; } protected: int m_nData = 10; }; class CMyDataEx : public CMyData { public: virtual void PrintData() { cout << "CMyDataEx: " << m_nData * 2 << endl; } }; int main() { CMyDataEx a; a.PrintData(); CMyData &b = a; b.PrintData(); a.TestFunc(); }


위의 예제에서 CMyData::PrintData() 함수를 가상 함수로 선언했는데, 이 함수는 내부 멤버 데이터인 m_nData의 값을 출력한다. 그리고 32번 행에서 이 PrintData() 함수를 재정의했다. 여기까지는 기존의 일반 베서드를 재정의한 것과 크게 다르지 않기 때문에 호출하게 되면 CMyDataEx 클래스의 PrintData() 메서드를 호출한게 된다.



CMyData  &b = a;

b.PrintData();

재밌는 코드가 등장하게 되는데 실형식은 CMyDataEx이며 참조 형식은 기본 클래스인 CMyData에 속한 참조자 b가 선언됐다. 그리고 b를 통해 PrintData()를 호출했습니다. 일반 메서드의 경우 실 형식은 중요하지 않고 참조 형식이 무엇인지에 따라 어떤 메 서드가 호출되는지 결정이 났지만 가상함수는 다르다. 가상 함수는 일반 메서와 달리 참조 형식이 무엇이든 실 형식의 메서드를 호출한다.


"일반 메서드는 참조 형식을 따르고, 가상함수는 실 형식을 따른다.



	
void TestFunc()
{
		cout << "***TestFunc()***" << endl;

		PrintData();
		cout << "****************" << endl;
}


PrintData(); 는 누구를 호출할까? TestFunc() 함수는 기본 클래스인 CMyData의 멤버이다. 그러므로 위의 PrintData()는 기본적으로 CMyData 클래스의 PrintData() 함수를 말하는 것이다. 그런데 문제는 PrintData() 함수가 '가상 함수'라는 사실이다. 이렇게 되면 지금 PrintData() 함수는 '미래'에 재정의된 함수일 수 있다.

만일 파생형식(자식)에서 PrintData() 가상 함수를 재정의한다면 위의 PrintData()는 미래의 함수를 호출하는 것이다.



------------- 실행 화면 -------------


CMyDataEx: 20

CMyDataEx: 20

***TestFunc()***

CMyDataEx: 20

****************

계속하려면 아무 키나 누르십시오 . . .

'C++' 카테고리의 다른 글

OSI 7계층, TCP/IP 4계층  (0) 2018.05.17
[C++] 가상함수 (Virtual)  (0) 2018.05.14
[C++] Template 템플릿  (0) 2018.05.13

클래스 템플릿

- '클래스 템플릿'은 클래스를 찍어내느 ㄴ모양자라고 생각하면 이해하기 쉽다. 그리고 이 모양자에 구멍이 뚫려 있는 부분은 '자료형'이다. 클래스 템플릿은 다음과 같인 선언할 수 있다.


template<typename T>

class 클래스명 {

.....

}


함수 템플릿처럼 선언에 앞서 template 예약어와 tpyename 예약어를 적어 넣어야한다. 그러나 함수 템플릿고 ㅏ달리 인스턴스르 ㄹ선언할떄는 typename을 반드시 적어야 한다.


template<typename T>

class MyData

{

public(T param) : m_Data(param) { }

T GetData() const { return m_Data; }


operator T() { return m_Data; }

void SetData(T param) { m_Data = param; }


private :

// T 형식의 멤버 변수 선언

T m_Data;


]


int _tmain(int argc_ TCJAR* argv[])

{

CMyData<int> a(5);

cout << a << endl;

CMyData<double> b(123.45);

cout << b << endl;

CMyData<char*> c("Hello");

cout << c << endl;


return 0;

}


이러한 예제 소스가 있을때 굵게 칠해진 행을 보면 클래스 템플릿으로 인스턴스를 선언할때 각각에 맞는 자료형을 정의했다 .이렇게 하면 int, double, char*에 맞는 클래스를 컴파일러가 찍어낸다. 참고로 찍어서만드어진 클래스를 '템플릿 클래스'라고 한다. 

Template 이라는 단어는 모형자라는 의미를 가진단어로, C++에서 템플릿은 어떤 제품을 만들어내는 틀, 예를 들어 붕어빵에 비교해 보자면, 붕어빵을 만들어 내는 틀을 템플릿이라 말 할 수 있다. 템플릿의 특징은 기능은 이미 결정되어 있지만, 데이터 타입은 결정되어 있지 않는다는 특징을 가지고 있다. 생성된 세 템플릿 클래스는 모두 동일하게 변환 생성자, 형변환 연산자, SetData() 메서드를 가진다. 


템플릿 매개변수

템플릿을 선언할 때 다음과 같이 형식을 여러개 작성할 수도 있습니다.

Template<Typename T, tpyename T2>


그런데 여러 형 식 중 일부는 다음고 ㅏ같이 형식을 구체적으로 작성해도 상관없다.

Template<Typename T, int nSize>




tmeplate<typename T, int nSize>

class CMyArray{

    ......

}


int _tmaint(int argc, _TCJAR* argv[])

{

CMyArray<int, r> arr;

arr[0] = 10;

arr[1] = 20;

arr[3] = 30;

...

}


tmeplate<typename T, int nSize>라고 선언했고 CMyArray<int, 3> arr; 라고 선언했다. 이렇게 함으로 arr 요소의 개수는 3이된다. 여기서 재밌는 사실은 템플릿 매개변수는 클래스 템플릿 내부에서도 모두 접근할 수 있다는 점이다. 




템플릿 특수화

- 템플릿을 사용하면 자료형에 관계없이 프로그램을 만들 수 있따. 그러나 간혹 특별한 형식이 있을 경우 나머지 다른 형식들과 전혀 다른 코드를 적용해야 할 때가 있씁니다. 가장 대표적인 예인 '포인터'는 일반적인 형식들과 달리 간접 지정 연산을 실행해야하는 경우가 있다. 또한 문자열에 '덧셈'을 적용할 경우 일반 형식과 전혀 다른 코드를 작성해야 한다.



함수 템플릿 특수화


template<typename T>

T Add(T a,T b) {

return a + b;

}


template<>

char* Add(char *pszLeft, char *pszRight)

{

int nLenLeft = strlen(pszLeft);

int nLenRight = strlen(pszRight);

char *pszResult = new char[nLenLeft + nLenRight = 1];


strcpy_s(pszResult, nLenLeft + 1, pszLeft);

strcpy_s(pszResult + nLenLeft, nLenRight + 1, pszRight);



return pszResult;

}


int _tmain(int argc, _TCHAR* argv[])

{

int nResult = Add<int>(3, 4);

cout << nResult << endl;


char *pszResult = Add<char*>("hello", "world");

cout << pszResult << endl;

delete [] pszResult


return 0;

}


위으 소스는 함수 템플릿인 Add()를 두가지 형태로 정의한 것이다. 여기서 두가지라고 한 것은 문자열을 더하는 경우와 나머지 모든 자료형을 위한 경우로 나눈 것이다. 한마디로 문자열을 특별히 분리해서 (특수화해서) 처리하는 것이다.

int nResult = Add<int>(3, 4); 호출한 Add() 템플릿 함수는 첫번째 함수에서 만들어지고 char *pszResult = Add<char*>("hello", "world"); 는 두번째 add 함수로 생성된다.


템플릿을 특수화할 때 typename을 아무것도 기술하지 않았다. 마치 함수를 다중 정의하듯 함수 템플릿을 여러 번 정의하는 경우 컴팡일러는 이를 


"특정 형식은 개발자인 내가 직접 정의할 테니 별도로 생성하지 말라"


는 것으로 인식한다. 다만 이와 같이 묵시적 의미가 전달되려면 두 매개 변수와 변환 형식이 모두 같아야한다. 


'C++' 카테고리의 다른 글

OSI 7계층, TCP/IP 4계층  (0) 2018.05.17
[C++] 가상함수 (Virtual)  (0) 2018.05.14
[C++] Template 템플릿  (0) 2018.05.13

일반적으로 소켓 프로그램은 서비스를 요청하는 클라이언트측과  클라이언트로부터의요청을 받아 서비스하는 서버측, 이렇게 두 곳에 상주하는 프로그램으로 구성된다. 우리가 구현할 소켓 스포르갬은 c언어로 작성했던 한 줄 짜리 문자열 출력 프로그램에 네트워크 기능을 부여하여 호스트사이세서 서로 통신하며 자료를 송수신할 수 있게 한것이다. 즉 클라이언트 프로그램이 네트워크상에서 통신 채널을 통해 서버측에 연결되면 서버 프로그램은 즉시 문자열 hello world를 클라이언트에게 전송하고 클라이언트 프로그램은 전송받은 문자열을 화면에 출력한다.


일반 프로그램에서는 문자열  출력이 한 컴퓨터에서 이루어졌던 것에 비해 소켓프로그램에서는 네트워크상에 있는 호스트 간에 문자열을 받아 출력하기 때문에 소켓과 같은 네트워크 연결 장치가 필요하다. 그리고 호스트 간에 서로 연결된 이후에는 소켓을 통해문자열을 송수신하느 코그다 있어야한다.


1. 연결 요청: 클라이언트 프로그램은 소켓 API 한수를 호출하여 서버 프로그램에 연결을 요청한다.

2. 문자열 전송 : 연결 요청을 받은 서버 프로그램은 클라이언트 프로그램과 연결되자마자 문자열 HELLO, WORLD를 클라이언트에게 전송한다.

3. 화면 출력 : 클라이언트 프로그램은 전송받은  문자열을 자신의 화면에 출력한다.


1번과 3번 과정은 클라이언트가 수행하는 기능이고 서버는 2번을 수행한다.




Windows 기반 MFC Socket 프로그램 구현

MS 윈도우 기반의 소켓 프로그램은 Win32 API 함수를 이용해서 개발하거나 MFC LIBㄹ을 이용해서 개발한다. MFC 라이브러리를 이용해보겠다.


MFC는 소켓과 관련해서 두 개의 클래스를 제공한다.

CObject

-> CAsyncSocket

-> CSocket


CObject 클래스에 상속된 CAsyncSocket 클래스는 비동기 소켓을 지원한다. 여기서 비동기 소켓이란 송수신 함수 등을 호출할 때호출하자마자 바로반환하고 다음 코드를 실행하는 소켓을 말한다. -> 비동기


CSocket은 CAsyncSocet 클래스를 상속한 클래스로 동기 소켓을 지원한다. 비동기 소켓과 달리 동기 소켓은 송수신 함수 등을 호출할 때 함수가 내부 코드를 모두 수행할때까지 반환핮지 않고 기다린다. -> 동기



클라이언트 프로그램

프로젝트명 : HelloClient

대화상자 기반, 고급기능에서 windows 소켓 체크


GUI 설계


컨트롤 

ID 

변수 

Caption 

Static Text 

IDC_STATIC_STATUS 

m_static_status 

서버가 보내준 자료를 출력합니다. 

Button Control 

IDC_BUTTON_CONNECT 

 

연결 




HelloClientDlg.h

#pragma once #include "afxwin.h" // CmfcsocketDlg dialog class CmfcsocketDlg : public CDialogEx { // Construction public: CmfcsocketDlg(CWnd* pParent = NULL); // standard constructor // Dialog Data #ifdef AFX_DESIGN_TIME enum { IDD = IDD_MFCSOCKET_DIALOG }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support // Implementation protected: HICON m_hIcon; // Generated message map functions virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: afx_msg void OnStnClickedStaticStatus(); CStatic m_static_status; public: afx_msg void OnBnClickedButtonConnect(); };

mfc 마법사를 통해 스태틱 컨트롤과 버튼 컨트롤에 멤버변수와 헨들러함수를 등록한다.






HelloClientDlg.cpp

void CmfcsocketDlg::OnBnClickedButtonConnect()

{

// TODO: Add your control notification handler code here

CSocket socket;

socket.Create();

socket.Connect(_T("127.0.0.1"), 9000);


int cbRcvd;

char buffer[1024];

CString strBuffer = _T("");


if ((cbRcvd = socket.Receive(buffer, 1024)) > 0) {

strBuffer = (LPCSTR)(LPSTR)buffer;

//strBuffer.Format("%s", buffer);

m_static_status.SetWindowText(strBuffer.Left(cbRcvd));

}

socket.Close();

}

등록한 버튼 클릭 함수를 구현한다.


위의 연결 버튼을 클릭하게 되면 OnBnClickedButtonConnect() 가 실행된다. 소켓 프로그램을 위해 CSocket 클래스의 socket 개개체를 생성해서 서버와 연결하고 서버로부터 문자열을 받아온다.


1. socket.create() 함수를 호출해서 소켓을 생성하고

2. socket.connect() 함수를 호출해서 IP주소와 포트를 통해 연결을 시도한다. ( 지금은 로컬호스트 주소 )

3. socket.receive() 함수를 호출해서 서버에서 전달한 문자열을 수신한다.





서버 프로그램

프로젝트명 : HelloServer

대화상자 기반, 고급기능에서 windows 소켓 체크


GUI 설계


 컨트롤

ID 

변수 

CAPTION 

Static Text 

IDC_STATIC_STATUS 

m_static_status 

Server Stop 

Button Control

IDC_BUTTON_START  

m_button_start 

시작 




1. CListenSocket 클래스 생성 (base CSockt 상속)

- 클라이언트의 연결 요청을 받으면 OnAccept 메세지 처리기가 실행되어 연결 요청을 처리한다.


ListenSocket.h

#pragma once #include "afxsock.h" class CHelloServerDlg; class CListenSocket : public CSocket { public: CListenSocket(CHelloServerDlg* pHelloServerDlg); ~CListenSocket(); CHelloServerDlg* m_pHelloServerDlg; public: virtual void OnAccept(int nErrorCode); // 속성창을 이용하면 자동으로 함수 등록가능 };

등록한 버튼 클릭 함수를 구현한다.



ListenSocket.cpp

#include "stdafx.h" #include "ListenSocket.h" #include "HelloServerDlg.h" CListenSocket::CListenSocket(CHelloServerDlg* pHelloServerDlg) { m_pHelloServerDlg = pHelloServerDlg; } CListenSocket::~CListenSocket() { } void CListenSocket::OnAccept(int nErrorCode) { // TODO: Add your specialized code here and/or call the base class m_pHelloServerDlg->ProcessAccept(); CSocket::OnAccept(nErrorCode); }

생성자 파라메터를 바꿔주고 OnAccept() 함수를 통해 인자로 받은 dlg 변수의 주소를 m_pHelloServerDlg 변수에 담는다.

클라이언트로부터 연결 요청이 오면 메시지 처리기 OnAccept가 호출된다. OnAccept 메세지 처리기에서는 연결 처리를 직접 하지 않고 이를 대화 상자 CHelloServerDlg 객체에서 처리하도록 CHelloServerDlg 객체의 메서드 ProcessAccept를 호출한다. 





2. CServiceSocket 클래스 생성 (base CSockt 상속)

- 클라이언트의 연결 요청을 받아들이고 해당 클라이언트에 대한 처리를 수행할 CServiceSocket객체를 생성





ServiceSocket.h

#pragma once #include "afxsock.h" class CHelloServerDlg; class CServiceSocket : public CSocket { public: CServiceSocket(CHelloServerDlg* pHelloServerDlg); ~CServiceSocket(); CHelloServerDlg* m_pHelloServerDlg; };

리슨소켓과 마찬가지로 메인 다이얼로그를 참조하기위해 변수선언 및 생성자 인자 수정을 해준다.




ServiceSocket.cpp

#include "stdafx.h" #include "ServiceSocket.h" #include "HelloServerDlg.h" CServiceSocket::CServiceSocket(CHelloServerDlg* pHelloServerDlg) { m_pHelloServerDlg = pHelloServerDlg; } CServiceSocket::~CServiceSocket() { }

ServiceSocket.h

#pragma once #include "afxsock.h" class CHelloServerDlg; class CServiceSocket : public CSocket { public: CServiceSocket(CHelloServerDlg* pHelloServerDlg); ~CServiceSocket(); CHelloServerDlg* m_pHelloServerDlg; };

리슨소켓과 마찬가지로 메인 다이얼로그를 참조하기위해 변수선언 및 생성자 인자 수정을 해준다.




HelloServerDlg.cpp

#pragma once #include "afxwin.h" #include "ListenSocket.h" #include "ServiceSocket.h" // CHelloServerDlg dialog class CHelloServerDlg : public CDialogEx { // Construction public: CHelloServerDlg(CWnd* pParent = NULL); // standard constructor // Dialog Data #ifdef AFX_DESIGN_TIME enum { IDD = IDD_HELLOSERVER_DIALOG }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support // Implementation protected: HICON m_hIcon; // Generated message map functions virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: CStatic m_static_status; CButton m_button_start; public: CListenSocket* m_pListenSocket; CServiceSocket* m_pServiceSocket; void ProcessAccept(); afx_msg void OnBnClickedButtonsStart(); };

헤더파일에 구현에 필요한 변수와 함수들을 선언해준다. 

OnBnClickButtonStart는 이벤트 처리 마법사를 이용하여 등록한다.



ServiceSocket.cpp

void CHelloServerDlg::ProcessAccept() { m_pServiceSocket = new CServiceSocket(this); char sndBuffer[] = "Hello, world"; if (m_pListenSocket->Accept(*m_pServiceSocket)) { m_static_status.SetWindowText(_T("Acceepted")); m_pServiceSocket->Send(sndBuffer, (int)strlen(sndBuffer)); m_static_status.SetWindowText(_T("Send Hello, World")); } else { delete m_pServiceSocket; } } void CHelloServerDlg::OnBnClickedButtonsStart() { // TODO: Add your control notification handler code here UINT nPort = 9000; m_pListenSocket = new CListenSocket(this); m_static_status.SetWindowText(_T("Create Listen Socket")); if (!m_pListenSocket->Create(nPort)) { m_static_status.SetWindowText(_T("Cannot Create Socket")); return; } else { m_static_status.SetWindowText(_T("Socket Create success")); if (!m_pListenSocket->Listen()) { m_static_status.SetWindowText(_T("can not listen")); return; } } }

위의 두개의 함수를 구현한다.


시작 버튼을 누르게 되면 CListenSocket 객체를 생성하고 CListenSocket 객체의 Create 메서드를 호출해서 클라이언트로부터 연결 요청을 받을 듣기 소켓을 생성한다. 그런 다음 CListenSockt 객체의 Listen 메서드를 호출해서 클라이언트로부터 연결 요청을 받을 수있는 LISTEN 상태가 된다.


클라이언트로부터 연결 요청이 외면 CListenSocket 개개체의 OnAccept 메서드가 실행된다. CListenSocket 객체의 OnAccept 메서드에서 클라이언트와의 연결처리를 수행하지 않고, 대화 상자 CHelloServerDlg 객체에서 일괄 처리할 수 있도록 CHelloServerDlg 객체의 ProcessAccept 메서드를 호출한다. CHelloServerDlg 객체의 ProcessAceept 메서드에서는 클라이언트와 연결하여 자료를 송수신할 CServiceSocket 객체를 생성하고, CListenSocket 객체의 Accept 메서드를 호출해서 CServiceSocket 객체와 클라이언트를 연결한다. 그런다음 CServicesOCKET 객체의 Send 메서드를 통해 즉시 클라이언트로 문자열 hello, word를 전송한다.




TCP/IP는 대표적인 광역 네트워크 프로토콜이다. 미국의 군사 네트워크에서 활용했떤 프로토콜이였으나 이제는 전세계로 묶는 네트워크 프로토콜로 발전했다. 


웹브라우져를 통해 URL이나 IP주소를 입력하면 해당 사이트에 접속하여 웹 페이지가 열린다. 너무나 간단해 보이지만 여기에는 아주 복잡한 네트워킹 과정이 담겨 있다. 웹 통신 프로토콜인 HTTP 프로토콜은 TCP/IP 프로토콜을 기반으로 만들어져있다.



IP주소

전세계를 연결하는 TCP/IP 네트워크에 접속하려면 IP주소를 하나 갖고 있어야한다. 이주소는 친구의 집 주소와 같은 형식은 아니지만 전 세계에서 중복되지 않는 유일한 숫자(IPV4 체계에서는 32비트 숮자)이다. 따라서 이 주소만 알면 주소지 컴퓨터로 정보를 전달할 수있다. 물론 상대뿐만 아니라 나도 유일한 IP주소를 가져야 한다.


친구에게 물건을 택배로 보낸다느 가정하에 먼저 할 일은 보낼물건을 포장하고 친구의 집 주소를 송장의 받는 사람 주소에 쓰게된다. 이렇게 송장에는 반드시 받는 사람과 받는사람의 주소를 함께 적는다. 이렇게 하면 보낼 준비는 끝난 것이다. 그 다음 택배회사에 전화를 할 것이고, 택배회사에서 물건을 가지러 오면 택배기사에게 물건을 전단하고 수령한 물건을 택배회사에서는 배달지에 따라 분류해서 지역별 집겨지로 보낸다. 그런 다음 택배기사는 배달지에 도착해서 받는 사람 주소에 친구가 정말 사는지 확인하고 물건을 전달한다. 


정보를 전달하는건 ISP회사(KT,SKT,LG)가 담당한다. 따라서 인터넷을 통해 정보를 보내려면 ISP에게서 회선을 임대한 후 인터넷으로 접속하는 유일한 IP주소를할당받고 상대 주소로 정보를 전송하거나 역으로 수신받는다.

최종적으로 정보를 수신하는 호스트의 운영체제는 어떤 프로세스가 정보를 수신해야 하는지 확인하여 처리를 완료한다.


인터넷 프로토콜 버전4는 32비트 주소체계를 갖고 있다. 32비트는 네 개의 8비트로 재구성되며, 각각의 값은 10진수로 표시하고 구분점으로 나누어진다. 

자신의 아이피 주소를 확인하려면 CMD에서 IPCONFIG 명령을 사용하면 확인 가능하다.


IP주소는 네트워크 ID와 호스트 ID로 나누어지는데 네트워크 ID는 네트워크를 식별하는 주소(서울시 종로구 종로동), 호스트 아이디는(X번지) 해당 네트워크에 속한 컴퓨터 주소이다.  네트워크 프로그래밍에서는 호스트라는 말을 사용하는데 IP주소를 갖는 장치가 반드시 PC나 서버 같은 컴퓨터만이 아니라 다양한 네트워크 장비도 될 수 있기 때문이다.



SOCKET

일반적으로 네트워크 프로그래밍이라 하면 TCP/IP SOCKET 프로그래밍을 의미한다. 바꿔서 말하면 소켓 프로그래밍 곧 네트워크 프로그래밍이라 할 수 있다. 그런데 여기서 말하는 소켓은 기존의 파일 개념과 유사하다. 일반적으로 파일이라 함은 보조기억장치에 젖아된 데이터를 말하기 마련인데, 좀더 정확히 말하자면 보조기억장치를 추상화한것이다.


하드디스크가 내부적으로 작동되는 원리르 모르더라도 파일을 열고 쓰고 닫을 수 있따면 우리는 하드시크를 다룬다고 할 수 있습니다. 마찬가지로 보통 LAN카드라고 부르는 네트워크 카드도 하나의 파일로 추상화가 가능하다. 이렇게 추상화된 파일에 정보를 저장하면 하드디스크에 저장되지 않고 네트워크 카드를 통해 외부로 전달된다.


파일이 장치를 추상화한 것이라고 가정할 때만 일 대상 장치가 네트워크 카드이면 파일이라는 말 대신에 소켓이라고 한다. 그러므로 소켓 프로맹이라는 것은 네트워크 카드를 추상화한 파일 포인터를 다루는 일로 정리된다. 그래서 우리가 파일에 대해 알고 있는 프로그래밍 지식 대부분이 소켓 프로그래밍에서 적용된다.


파일의 정보를 읽거나 쓰려면 파일을 열어야 하는것처럼 소켓도 핸들을 열어서 입출력을 하게된다. 물론 사용한후에 핸들을 닫아야 한다. 여기서 조금 전에 설명한 TCP/IP에 대한 기초 지식을 결합하면 소켓에 대한 정의가 끝난다



이후에 MFC를 이용한 TCP/IP 소켓프로그래밍 채팅프로그램을 생성해보겠다.

+ Recent posts

티스토리 툴바