7.4.9 EH메신저 DBM 라이브러리 설계 및 구현 [TCP/IP 소켓 프로그래밍 with 윈도우즈]

이번에는 DBM 라이브러리를 설계 및 구현합시다.

DBM 라이브러리에는 비지니스 계층과 데이터 계증 사이에 주고 받는 메시지들을 정의할 것입니다. 응용 프로토콜 스택 정의에서 IDExist(아이지 존재 확인 요청), IDExistAck(아이디 존재 확인 응답), AddUserInfo(계정 정보 추가), UserSts(사용자 상태 요청), UserStsAck(사용자 상태 요청 응답), IsCorrect(패스워드 일치 확인 요청), IsCorrectAck(패스워드 일치 확인 요청 응답), ChangeSts(상태 변경 요청)이 있습니다.

DBM 라이브러리는 비지니스 계층의 서버와 데이터 계층의 Dbm 서버가 사용합니다.

[그림 7.18] DBM 관련 노드 컴포넌트 다이어그램

 이제 DBM 라이브러리를 작성합시다. DBM 라이브러리는 DbmLib 이름으로 만들게요.

DBM 라이브러리에 정의할 메시지 종류마다 클래스로 정의할게요. 먼저 EH 메신저 솔루션에 DbmLib 이름으로 Win2프로젝트를 추가하고 DLL 형태로 만드세요.

작성 원리는 가입(로그, 상태) 라이브러리 작성 원리와 같습니다. DBM 라이브러리에서 공통으로 포함해서 사용할 Dbm.h 파일을 Common 프로젝트에 추가합니다.

#pragma once
#include "..\\common\\EHPacket.h"
#pragma comment(lib,"..\\Debug\\EHPacketLib")
#ifdef DBM038IUPHDFJKDIFEWFKDSIFHWELKJFHOISUDFHK
#define DBM_DLL  __declspec(dllexport)
#else
#define DBM_DLL  __declspec(dllimport)
#endif

상태의 종류를 매크로 상수로 정의합시다.

#define STS_UNREG   0x00
#define STS_REG     0x01
#define STS_LOGGING 0x02
#define STS_LOGGED  0x03

IDExist 클래스를 구현합시다. IDExist.h 파일은 Common 프로젝트에 추가하고 IDExist.cpp 파일은 DbmLib 프로젝트에 추가하여 구현합니다. 구현 방법은 앞에서 만들었던 다른 메시지들과 같으므로 코드 설명은 생략할게요.

#pragma once
#include "Dbm.h"
#pragma warning(disable:4251)
#include <string>
using namespace std;
class DBM_DLL IDExist
{
    string id;
public:
    IDExist(string id);
    IDExist(EHPacket *ep);
    string GetId()const;
    void Serialize(SOCKET sock);
};

다음은 IDExist.cpp 파일을 작성한 코드입니다.

#define DBM038IUPHDFJKDIFEWFKDSIFHWELKJFHOISUDFHK
#include "..\\common\\IDExist.h"
#include "..\\Common\\ehmsg.h"
IDExist::IDExist(string id)
{
    this->id = id;
}
IDExist::IDExist(EHPacket *ep)
{
    int idlen = 0;
    char id[256]="";
    ep->DePacketize(&idlen,sizeof(idlen));
    ep->DePacketize(id,idlen);
    this->id = id;
}
string IDExist::GetId()const
{
    return id;    
}
void IDExist::Serialize(SOCKET sock)
{
    EHPacket ep(MID_IDEXIST);
    int idlen = id.length() + 1;
    ep.Packetize(&idlen,sizeof(idlen));
    ep.Packetize((void *)id.c_str(),idlen);
    ep.Serialize(sock);
}

IDExistAck 클래스를 작성합시다. 마찬가지로 헤더 파일은 Common 프로젝트에 소스 파일은 DbmLib 프로젝트에 추가합니다.

다음은 IDExistAck.h 파일을 작성한 코드입니다.

#pragma once
#include "Dbm.h"
#define RES_ID_NOTEXIST          0
#define RES_ID_EXIST             1
class DBM_DLL IDExistAck
{
    int result;
public:
    IDExistAck(int result);
    IDExistAck(EHPacket *ep);
    int GetResult()const;
    void Serialize(SOCKET sock);
};

다음은 IDExistAck.cpp 파일을 작성한 코드입니다.

#define DBM038IUPHDFJKDIFEWFKDSIFHWELKJFHOISUDFHK
#include "..\\common\\IDExistAck.h"
#include "..\\Common\\ehmsg.h"
IDExistAck::IDExistAck(int result)
{
    this->result = result;
}
IDExistAck::IDExistAck(EHPacket *ep)
{
    ep->DePacketize(&result,sizeof(result));
}
int IDExistAck::GetResult()const
{
    return result;
}
void IDExistAck::Serialize(SOCKET sock)
{
    EHPacket ep(MID_IDEXISTACK);
    ep.Packetize(&result,sizeof(result));
    ep.Serialize(sock);
}

AddUserInfo 메시지를 정의합시다. 마찬가지로 헤더 파일은 Common 프로젝트에 소스 파일은 DbmLib 프로젝트에 추가합니다.

다음은 AddUserInfo.h 파일을 작성한 코드입니다.

#pragma once
#include "Dbm.h"
#pragma warning(disable:4251)
#include <string>
using namespace std;
class DBM_DLL AddUserInfo
{
    string id;
    string pw;
    string name;
public:
    AddUserInfo(string id,string pw,string name);
    AddUserInfo(EHPacket *ep);
    string GetId()const;
    string GetName()const;
    string GetPW()const;
    void Serialize(SOCKET sock);
};

다음은 AddUserInfo.cpp 파일을 작성한 코드입니다.

#define DBM038IUPHDFJKDIFEWFKDSIFHWELKJFHOISUDFHK
#include "..\\common\\AddUserInfo.h"
#include "..\\Common\\ehmsg.h"
AddUserInfo::AddUserInfo(string id,string pw, string name)
{
    this->id = id;
    this->pw = pw;
    this->name = name;
}
AddUserInfo::AddUserInfo(EHPacket *ep)
{
    int idlen = 0;	
    char id[256]="";
    ep->DePacketize(&idlen,sizeof(idlen));
    ep->DePacketize(id,idlen);
    int pwlen=0;
    char pw[256]="";
    ep->DePacketize(&pwlen,sizeof(pwlen));
    ep->DePacketize(pw,pwlen);

    int namelen = 0;
    char name[256]="";
    ep->DePacketize(&namelen,sizeof(namelen));
    ep->DePacketize(name,namelen);

    this->id = id;
    this->pw = pw;
    this->name = name;
}
string AddUserInfo::GetId()const
{
    return id;    
}
string AddUserInfo::GetName()const
{
    return name;    
}
string AddUserInfo::GetPW()const
{
    return pw;    
}
void AddUserInfo::Serialize(SOCKET sock)
{
    EHPacket ep(MID_ADDUSERINFO);
    int idlen = id.length() + 1;
    ep.Packetize(&idlen,sizeof(idlen));
    ep.Packetize((void *)id.c_str(),idlen);
    int pwlen = pw.length()+1;
    ep.Packetize(&pwlen,sizeof(pwlen));
    ep.Packetize((void *)pw.c_str(),pwlen);
    int namelen = name.length() + 1;
    ep.Packetize(&namelen,sizeof(namelen));
    ep.Packetize((void *)name.c_str(),namelen);
    ep.Serialize(sock);
}

UserSts(사용자 상태 요청)메시지를 정의합시다. 마찬가지로 헤더 파일은 Common 프로젝트에 소스 파일은 DbmLib 프로젝트에 추가합니다. 다음은 UserSts.h 파일을 작성한 코드입니다.

#pragma once
#include "Dbm.h"
#pragma warning(disable:4251)
#include <string>
using namespace std;
class DBM_DLL UserSts
{
    string id;
public:
    UserSts(string id);
    UserSts(EHPacket *ep);
    string GetId()const;
    void Serialize(SOCKET sock);
};

다음은 UserSts.cpp 파일을 작성한 코드입니다.

#define DBM038IUPHDFJKDIFEWFKDSIFHWELKJFHOISUDFHK
#include "..\\common\\UserSts.h"
#include "..\\Common\\ehmsg.h"
UserSts::UserSts(string id)
{
    this->id = id;
}
UserSts::UserSts(EHPacket *ep)
{
    int idlen = 0;
    char id[256]="";
    ep->DePacketize(&idlen,sizeof(idlen));
    ep->DePacketize(id,idlen);
    this->id = id;
}
string UserSts::GetId()const
{
    return id;    
}
void UserSts::Serialize(SOCKET sock)
{
    EHPacket ep(MID_USERSTS);
    int idlen = id.length() + 1;
    ep.Packetize(&idlen,sizeof(idlen));
    ep.Packetize((void *)id.c_str(),idlen);
    ep.Serialize(sock);
}

사용자 상태 응답 메시지인 UserStsAck 클래스를 작성합시다. 마찬가지로 헤더 파일은 Common 프로젝트에 소스 파일은 DbmLib 프로젝트에 추가합니다.

다음은 UserStsAck.h 파일을 작성한 코드입니다.

#pragma once
#include "Dbm.h"
class DBM_DLL UserStsAck
{
    int status;
public:
    UserStsAck(int status);
    UserStsAck(EHPacket *ep);
    int GetStatus()const;
    void Serialize(SOCKET sock);
};

다음은 UserStsAck.cpp 파일을 작성한 코드입니다.

#define DBM038IUPHDFJKDIFEWFKDSIFHWELKJFHOISUDFHK
#include "..\\common\\UserStsAck.h"
#include "..\\Common\\ehmsg.h"
UserStsAck::UserStsAck(int status)
{
    this->status = status;
}
UserStsAck::UserStsAck(EHPacket *ep)
{
    ep->DePacketize(&status,sizeof(status));
}
int UserStsAck::GetStatus()const
{
    return status;
}
void UserStsAck::Serialize(SOCKET sock)
{
    EHPacket ep(MID_USERSTSACK);
    ep.Packetize(&status,sizeof(status)); 
    ep.Serialize(sock);
}

비밀번호가 일치하는지 확인 요청하는 IsCorrect 메시지를 정의합시다. 마찬가지로 헤더 파일은 Common 프로젝트에 소스 파일은 DbmLib 프로젝트에 추가합니다.

다음은 IsCorrect.h 파일을 작성한 코드입니다.

#pragma once
#include "Dbm.h"
#pragma warning(disable:4251)
#include <string>
using namespace std;
class DBM_DLL IsCorrect
{
    string id;
    string pw;
public:
    IsCorrect(string id,string pw);
    IsCorrect(EHPacket *ep);
    string GetId()const;
    string GetPW()const;
    void Serialize(SOCKET sock);
};

다음은 IsCorrect.cpp 파일을 작성한 코드입니다.

#define DBM038IUPHDFJKDIFEWFKDSIFHWELKJFHOISUDFHK
#include "..\\common\\IsCorrect.h"
#include "..\\Common\\ehmsg.h"
IsCorrect::IsCorrect(string id,string pw)
{
    this->id = id;
    this->pw = pw;
}
IsCorrect::IsCorrect(EHPacket *ep)
{
    int idlen = 0;
    char id[256]="";
    ep->DePacketize(&idlen,sizeof(idlen));
    ep->DePacketize(id,idlen);

    int pwlen=0;
    char pw[256]="";
    ep->DePacketize(&pwlen,sizeof(pwlen));
    ep->DePacketize(pw,pwlen);

    this->id = id;
    this->pw = pw;
}
string IsCorrect::GetId()const
{
    return id;
}
string IsCorrect::GetPW()const
{
    return pw;
}
void IsCorrect::Serialize(SOCKET sock)
{
    EHPacket ep(MID_ISCORRECT);
    int idlen = id.length() + 1;
    ep.Packetize(&idlen,sizeof(idlen));
    ep.Packetize((void *)id.c_str(),idlen);
    int pwlen = pw.length()+1;
    ep.Packetize(&pwlen,sizeof(pwlen));
    ep.Packetize((void *)pw.c_str(),pwlen);
    ep.Serialize(sock);
}

비밀번호 일치 요청에 관한 응답 메시지인 IsCorrectAck를 정의합시다. 마찬가지로 헤더 파일은 Common 프로젝트에 소스 파일은 DbmLib 프로젝트에 추가합니다.

다음은 IsCorrectAck.h 파일을 작성한 코드입니다.

#pragma once
#include "Dbm.h"
#define IDPW_NOTCORRECT          0
#define IDPW_CORRECT                1
class DBM_DLL IsCorrectAck
{
    int result;
public:
    IsCorrectAck(int result);
    IsCorrectAck(EHPacket *ep);
    int GetResult()const;
    void Serialize(SOCKET sock);
}; 

다음은 IsCorrectAck.cpp 파일을 작성한 코드입니다.

#define DBM038IUPHDFJKDIFEWFKDSIFHWELKJFHOISUDFHK
#include "..\\common\\IsCorrectAck.h"
#include "..\\Common\\ehmsg.h"
IsCorrectAck::IsCorrectAck(int result)
{
    this->result = result;
}
IsCorrectAck::IsCorrectAck(EHPacket *ep)
{
    ep->DePacketize(&result,sizeof(result));
}
int IsCorrectAck::GetResult()const
{
    return result;
}
void IsCorrectAck::Serialize(SOCKET sock)
{
    EHPacket ep(MID_ISCORRECTACK);
    ep.Packetize(&result,sizeof(result)); 
    ep.Serialize(sock);
}

상태 변경을 요청인 ChangeSts 메시지를 정의합시다. 마찬가지로 헤더 파일은 Common 프로젝트에 소스 파일은 DbmLib 프로젝트에 추가합니다.

다음은 ChangeSts.h 파일을 작성한 코드입니다.

#pragma once
#include "Dbm.h"
#pragma warning(disable:4251)
#include <string>
using namespace std;
class DBM_DLL ChangeSts
{
    string id;
    int status;
public:
    ChangeSts(string id,int status);
    ChangeSts(EHPacket *ep);
    string GetId()const;
    int GetStatus()const;
    void Serialize(SOCKET sock);
};

다음은 ChangeSts.cpp 파일을 작성한 코드입니다.

#define DBM038IUPHDFJKDIFEWFKDSIFHWELKJFHOISUDFHK
#include "..\\common\\ChangeSts.h"
#include "..\\Common\\ehmsg.h"
ChangeSts::ChangeSts(string id,int status)
{
    this->id = id;
    this->status = status;
}
ChangeSts::ChangeSts(EHPacket *ep)
{
    int idlen = 0;
    char id[256]="";
    ep->DePacketize(&idlen,sizeof(idlen));
    ep->DePacketize(id,idlen);
    this->id = id;
    ep->DePacketize(&status, sizeof(status));
}
string ChangeSts::GetId()const
{
    return id;
}

int ChangeSts::GetStatus()const
{
    return status;
}
void ChangeSts::Serialize(SOCKET sock)
{
    EHPacket ep(MID_CHANGESTS);
    int idlen = id.length() + 1;
    ep.Packetize(&idlen,sizeof(idlen));
    ep.Packetize((void *)id.c_str(),idlen);
    ep.Packetize(&status,sizeof(status));
    ep.Serialize(sock);
}

계정 정보를 삭제하는 RemoveUser 메시지를 정의합시다. 마찬가지로 헤더 파일은 Common 프로젝트에 소스 파일은 DbmLib 프로젝트에 추가합니다.

다음은 RemoveUser.h 파일을 작성한 코드입니다.

#pragma once
#include "Dbm.h"
#pragma warning(disable:4251)
#include <string>
using namespace std;

class DBM_DLL RemoveUser
{
    string id;
public:
    RemoveUser(string id);
    RemoveUser(EHPacket *ep);
    string GetId()const;
    void Serialize(SOCKET sock);
};

다음은 RemoveUser.cpp 파일을 작성한 코드입니다.

#define DBM038IUPHDFJKDIFEWFKDSIFHWELKJFHOISUDFHK
#include "..\\common\\RemoveUser.h"
#include "..\\Common\\ehmsg.h"
RemoveUser::RemoveUser(string id)
{
	this->id = id;
}


RemoveUser::RemoveUser(EHPacket *ep)
{
    int idlen = 0;
    char id[256]="";
    ep->DePacketize(&idlen,sizeof(idlen));
    ep->DePacketize(id,idlen);
    this->id = id;
}
string RemoveUser::GetId()const
{
    return id;
}
void RemoveUser::Serialize(SOCKET sock)
{
    EHPacket ep(MID_REMOVEUSER);
    int idlen = id.length() + 1;
    ep.Packetize(&idlen,sizeof(idlen));
    ep.Packetize((void *)id.c_str(),idlen);
    ep.Serialize(sock);
}

DBM 라이브러리 테스트는 가입(로그, 상태) 라이브러리 테스트 방법과 일치합니다. 이미 많은 반복을 하였으므로 여러분에게 맡기고 여기에서는 생략할게요.