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

이번에는 로그 라이브러리가 정상적으로 동작하는지 확인하는 테스트 프로그램을 작성해 봅시다.

먼저 콘솔 응용 프로젝트로 테스트 로그 서버(TracerLogServer)를 추가합니다. 그리고 Program.cpp 소스 파일을 추가하고 필요한 헤더 파일을 포함합니다.

#include "..\\Common\\EHPacket.h"
#include "..\\Common\\LogInReq.h"
#include "..\\Common\\LogInRes.h"
#include "..\\Common\\LogOutReq.h"
#include "..\\Common\\ehmsg.h"

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

#pragma comment(lib,"ws2_32")
#pragma comment(lib,"..\\Debug\\EHPacketLib")
#pragma comment(lib,"..\\Debug\\LogLib")
#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 LogInReqProc(SOCKET sock,EHPacket *ep);
void LogInResProc(SOCKET sock,EHPacket *ep);
void LogOutReqProc(SOCKET sock,EHPacket *ep);
DWORD WINAPI DoIt(LPVOID pin)
{
    SOCKET dosock = (SOCKET)pin;
    EHPacket ep(dosock);
    switch(ep.GetMsgId())
    {
    case MID_LOGINREQ: LogInReqProc(dosock,&ep); break;
    case MID_LOGINRES: LogInResProc(dosock,&ep); break;
    case MID_LOGOUTREQ: LogOutReqProc(dosock,&ep); break;
    }
    closesocket(dosock);
    return 0;
}
void LogInReqProc(SOCKET sock,EHPacket *ep)
{
    LogInReq lr(ep);
    cout<<"로긴 요청"<<endl;
    cout<<"아이디:"<<lr.GetId()<<" 비밀번호:"<<lr.GetPW()<<endl;
}

void LogInResProc(SOCKET sock,EHPacket *ep)
{
    LogInRes lr(ep);
    cout<<"로긴 요청 응답"<<endl;
    switch(lr.GetResult())
    {
    case LOGIN_RES_OK:  cout<<"로긴 성공"<<endl; break;
    case LOGIN_RES_NOTEXIST: cout<<"아이디 없음"<<endl; break;
    case LOGIN_RES_LOGGED: cout<<"이미 로긴 중"<<endl; break;
    case LOGIN_RES_NOTCORRECT: cout<<"비밀번호 불일치"<<endl; break;
    }
}
void LogOutReqProc(SOCKET sock,EHPacket *ep)
{
    LogOutReq lor(ep);
    cout<<"로그 아웃 요청"<<endl;
    cout<<"아이디:"<<lor.GetId()<<endl;
}

콘솔 응용 프로젝트로 테스트 로그 클라이언트(TracerLogClient)를 추가합니다. Program.cpp 소스 파일을 추가하고 필요한 헤더 파일을 포함합니다. 가입 클라이언트 작성 방법과 같으므로 코드 설명은 생략할게요.

#include "..\\Common\\EHPacket.h"
#include "..\\Common\\LogInReq.h"
#include "..\\Common\\LogInRes.h"
#include "..\\Common\\LogOutReq.h"
#include "..\\Common\\ehmsg.h"
#pragma comment(lib,"ws2_32")
#pragma comment(lib,"..\\Debug\\EHPacketLib")
#pragma comment(lib,"..\\Debug\\LogLib")
#include <iostream>
using namespace std;
SOCKET Connect(const char *ip, int port)
{
    SOCKET sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(sock == -1){return -1;}
    SOCKADDR_IN servaddr = {0};
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr(ip);
    servaddr.sin_port = htons(port);
    int re = 0;
    re = connect(sock,(SOCKADDR *)&servaddr,sizeof(servaddr));
    if(re == -1){ return -1; }
    return sock;
}

로긴 요청 메시지를 전송하는 함수를 작성하세요.

void SendLogInReq(string id,string pw)
{
    SOCKET sock;
    LogInReq lr(id,pw);
    cout<<"로긴 요청 전송"<<endl;
    cout<<"아이디:"<<lr.GetId()<<" 비밀번호:"<<lr.GetPW()<<endl;
    sock = Connect("192.168.34.50",10200);
    lr.Serialize(sock);
    closesocket(sock);
}

로긴 응답 메시지를 전송하는 함수를 작성하세요.

void SendLogInRes(int result)
{
    SOCKET sock;
    LogInRes lr(result);
    cout<<"로긴 요청 응답 전송"<<endl;
    switch(result)
    {
    case LOGIN_RES_OK:  cout<<"로긴 성공"<<endl; break;
    case LOGIN_RES_NOTEXIST: cout<<"아이디 없음"<<endl; break;
    case LOGIN_RES_LOGGED: cout<<"이미 로긴 중"<<endl; break;
    case LOGIN_RES_NOTCORRECT: cout<<"비밀번호 불일치"<<endl; break;
    }
    sock = Connect("192.168.34.50",10200);//서버 IP 주소를 변경하세요.
    lr.Serialize(sock);
    closesocket(sock);
}

로그 아웃 요청하는 함수를 작성하세요.

void SendLogOutReq(string id)
{
    SOCKET sock;
    LogOutReq lor(id);
    cout<<"로그 아웃 전송"<<endl;
    cout<<"아이디:"<<lor.GetId()<<endl;
    sock = Connect("192.168.34.50",10200);//서버 IP 주소를 변경하세요.
    lor.Serialize(sock);
    closesocket(sock);
}
void StartTestClient()
{
    SendLogInReq("hgd","abc");
    SendLogInRes(LOGIN_RES_OK);
    SendLogInRes(LOGIN_RES_NOTEXIST);
    SendLogOutReq("hgd");
    SendLogInRes(LOGIN_RES_LOGGED);
    SendLogInRes(LOGIN_RES_NOTCORRECT);
    SendLogInReq("ehpub","abc");
}
int main()
{
    WSADATA wsadata;
    WSAStartup(MAKEWORD(2,2),&wsadata);
    StartTestClient();
    WSACleanup();
    return 0;
}