7.4.4 EH 메신저 가입 라이브러리 테스트 [TCP/IP 소켓 프로그래밍 with 윈도우즈]

이번에는 EHPacket 라이브러리와 가입 라이브러리가 정상적으로 동작하는지 확인하는 테스트 프로그램을 작성해 봅시다. 여러 컴포넌트로 구성하는 프로젝트를 만들 때에 컴포넌트 별로 단위 테스트를 수행하는 작업을 거쳐야 통합 테스트에서 예상하지 못한 비용을 줄일 수 있습니다.

먼저 콘솔 응용 프로젝트로 테스트 가입 서버(TracerRegServer)를 추가합니다. 프로젝트에 Program.cpp 파일을 추가하여 코드를 작성합니다. 먼저 필요한 헤더 파일을 포함합니다.

#include "..\\Common\\EHPacket.h"
#include "..\\Common\\RegReq.h"
#include "..\\Common\\RegRes.h"
#include "..\\Common\\UnRegReq.h"
#include "..\\Common\\ehmsg.h"

윈속 라이브러리와 EH 패킷 라이브러리와 가입 라이브러리를 참조 추가합니다.

#pragma comment(lib,"ws2_32")
#pragma comment(lib,"..\\Debug\\EHPacketLib")
#pragma comment(lib,"..\\Debug\\RegLib")
#include <iostream>
using namespace std;

진입점인 main에서는 윈속 초기화와 테스트 서버 가동 및 윈속 해제화를 수행합니다.

void StartTestServer();
int main()
{
    WSADATA wsadata;
    WSAStartup(MAKEWORD(2,2),&wsadata);
    StartTestServer();
    WSACleanup();
    return 0;
}

테스트 서버 가동 함수를 작성합시다. 앞에서 설명한 내용들이므로 코드 설명은 생략할게요.

struct in_addr GetDefaultMyAddr();
DWORD WINAPI DoIt(LPVOID pin);
void StartTestServer()
{
    SOCKET sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(sock == -1){ printf("소켓 생성 실패!\n"); return;}
    SOCKADDR_IN servaddr = {0};
    servaddr.sin_family = AF_INET;//PF_INET;
    servaddr.sin_addr = GetDefaultMyAddr();
    servaddr.sin_port = htons(10200);
    int re = 0;
    re = bind(sock,(SOCKADDR *)&servaddr,sizeof(servaddr));
    if(re == -1){ printf("bind 실패\n"); return; }
    re= listen(sock,5);
    SOCKADDR_IN clientaddr;
    int len = sizeof(clientaddr);
    SOCKET dosock;
    DWORD ThreadID;
    while(1)
    {
        dosock = accept(sock,(SOCKADDR *)&clientaddr, &len);
        //클라이언트와 통신할 쓰레드 생성
        CloseHandle(CreateThread(0,0,DoIt,(LPVOID)dosock,0,&ThreadID));
    }
}

struct in_addr GetDefaultMyAddr()
{
    char hostname[256]="";
    gethostname(hostname,255);
    hostent *hentry =  gethostbyname(hostname);
    struct in_addr addr={0};
    while(hentry && hentry->h_name)
    {
        if(hentry->h_addrtype == AF_INET)
        {
            memcpy(&addr,hentry->h_addr_list[0],sizeof(addr));
            return addr;
        }
        hentry++;
    }
    return addr;
}

가입 테스트 클라이언트가 연결한 이후에 테스트로 보내는 패킷을 받아 처리하는 루틴을 구현합시다.

void RegReqProc(SOCKET sock,EHPacket *ep);
void RegResProc(SOCKET sock,EHPacket *ep);
void UnRegReqProc(SOCKET sock,EHPacket *ep);
DWORD WINAPI DoIt(LPVOID pin)
{

쓰레드 진입점에 전달한 인자는 클라이언트와 통신에 사용할 소켓입니다.

    SOCKET dosock = (SOCKET)pin;

먼저 클라이언트에서 전송한 패킷을 수신합니다.

    EHPacket ep(dosock);

그리고 메시지 아이디에 따라 각 메시지 처리 루틴을 호출합니다.

    switch(ep.GetMsgId())
    {
    case MID_REGREQ: RegReqProc(dosock,&ep); break;
    case MID_REGRES: RegResProc(dosock,&ep); break;
    case MID_UNREGREQ: RegResProc(dosock,&ep); break;
    }

처리 루틴을 마치면 소켓을 닫습니다.

    closesocket(dosock);
    return 0;
}

가입 요청 메시지 처리 루틴입니다.

void RegReqProc(SOCKET sock,EHPacket *ep)
{

먼저 EHPacket을 가입 요청 패킷으로 전환합니다.

    RegReq rr(ep);

그리고 확인을 위해 가입 메시지에 전달한 정보를 출력합니다.

    cout<<"가입 요청"<<endl;
    cout<<"아이디:"<<rr.GetId()<<" 비밀번호:"<<rr.GetPW()<<" 이름:"<<rr.GetName()<<endl;
}

가입 요청 응답 메시지 처리 루틴입니다. 처리 방법은 같습니다.

void RegResProc(SOCKET sock,EHPacket *ep)
{

먼저 EHPacket을 가입 요청 응답 패킷으로 전환합니다.

    RegRes rr(ep);

요청 응답 결과를 출력합니다.

    cout<<"가입 요청 응답"<<endl;
    if(rr.GetResult() == REG_RES_OK)
    {
        cout<<"가입 성공"<<endl;
    }
    else
    {
        cout<<"가입 실패"<<endl;
    }
}

탈퇴 요청 메시지 처리 루틴입니다. 처리 방법은 같습니다.

void UnRegReqProc(SOCKET sock,EHPacket *ep)
{

먼저 EHPacket을 탈퇴 요청 패킷으로 전환합니다.

    UnRegReq urr(ep);

탈퇴 요청 정보를 출력합니다.

    cout<<"탈퇴 요청"<<endl;
    cout<<"아이디:"<<urr.GetId()<<endl;
}