7.5.3 EH 메신저 – LogSVC 구현 [TCP/IP 소켓 프로그래밍 with 윈도우즈]

LogSVC를 구현합시다. EH 메신저 솔루션에 LogSVC 이름의 콘솔 응용 프로젝트를 만드세요. 그리고 이 책에서는 LogSVC를 구현한 이후에 테스트 프로젝트를 만들고 테스트하는 부분은 다루지 않을게요.

LogSVC 프로젝트에 Program.cpp 파일을 추가하여 소스를 구현합시다.

#include "..\\Common\\EHMessenger.h"
#pragma comment(lib,"ws2_32")
#pragma comment(lib,"..\\Debug\\EHPacketLib")
#pragma comment(lib,"..\\Debug\\LogLib")
#pragma comment(lib,"..\\Debug\\DbmLib")
#pragma comment(lib,"..\\Debug\\EHWrapSocketLib")
#include <iostream>
using namespace std;

진입점 main 함수에서는 윈속 초기화 후에 로그 서버를 가동하고 윈속을 해제화합니다.

void StartLogServer();
int main()
{
    WSADATA wsadata;
    WSAStartup(MAKEWORD(2,2),&wsadata);
    StartLogServer();
    WSACleanup();
    return 0;
}
DWORD WINAPI DoIt(LPVOID pin);
void StartLogServer()
{
    SOCKET sock = EHWrapSocket::CreateTCPServer(LOG_PORT,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));
    }
}

로그 서버에서는 로긴 요청과 로그 아웃 요청 메시지를 처리합니다.

void LogInProc(SOCKET sock,EHPacket *ep);
void LogOutReqProc(SOCKET sock,EHPacket *ep);
DWORD WINAPI DoIt(LPVOID pin)
{
    SOCKET sock = (SOCKET)pin;
    EHPacket ep(sock);
    switch(ep.GetMsgId())
    {
    case MID_LOGINREQ: LogInProc(sock,&ep);break;
    case MID_LOGOUTREQ: LogOutReqProc(sock,&ep); break;
    }
    closesocket(sock);
    return 0;
}

로긴 요청 메시지 처리 함수를 작성합시다.

void LogInProc(SOCKET sock,EHPacket *ep)
{

수신한 메시지를 로긴 요청 메시지로 변환합니다.

    cout<<"로긴 요청 수신"<<endl;
    LogInReq lr(ep);

Dbm 서비스에 연결하여 아이디 존재 확인 요청 메시지를 전송합니다.

    IDExist ie(lr.GetId());
    SOCKET clisock = EHWrapSocket::Connect(DBM_IP,DBM_PORT);
    cout<<"아이디 존재 확인 요청 메시지 전송"<<endl;
    ie.Serialize(clisock);

Dbm 서비스로부터 응답 메시지를 수신합니다.

    EHPacket rep(clisock);
    closesocket(clisock);

수신한 메시지가 아이디 존재  확인 응답 메시지가 아니면 오류입니다.

    if(rep.GetMsgId() != MID_IDEXISTACK)
    {
        cout<<"오류!!! 아이디 존재 확인 응답 메시지가 아님"<<endl;
        return;
    }

아이디 존재 확인 응답 메시지로 변환합니다.

    cout<<"아이디 존재 확인 응답 메시지 수신"<<endl;
    IDExistAck iea(&rep);
    int result = LOGIN_RES_OK;

만약 아이디 존재하지 않으면 로긴 결과로 아이디 존재하지 않음을 설정합니다.

    if(iea.GetResult() == RES_ID_NOTEXIST)
    {
        result = LOGIN_RES_NOTEXIST;
        cout<<"아이디 존재하지 않음"<<endl;
    }

아이디가 존재하면 다음 처리를 합니다.

    else
    {

Dbm 서비스에 연결하여 상태 확인 요청 메시지를 전송합니다.

        UserSts us(lr.GetId());
        clisock = EHWrapSocket::Connect(DBM_IP,DBM_PORT);
        cout<<"상태 확인 요청 메시지 전송"<<endl;
        us.Serialize(clisock);

Dbm 서비스로부터 응답 메시지를 수신합니다.

        EHPacket rep2(clisock);
        closesocket(clisock);

만약 수신한 메시지가 상태 확인 응답 메시지가 아니면 오류입니다.

        if(rep2.GetMsgId() != MID_USERSTSACK)
        {
            cout<<"오류!!! 상태 확인 응답 메시지가 아님"<<endl;
            return;
        }

수신한 메시지를 상태 확인 응답 메시지로 변환합니다.

        cout<<"상태 확인 응답 메시지 수신"<<endl;
        UserStsAck usa(&rep2);

만약 결과가 STS_REG가 아니라면 이미 로긴 중이거나 로긴 상태입니다.

        if(usa.GetStatus() != STS_REG)
        {
            result = LOGIN_RES_LOGGED;
            cout<<"로긴할 수 없는 상태입니다."<<endl;
        }

그렇지 않으면  Dbm 서비스에 연결하여 패스워드 일치 확인 메시지를 전송합니다.

        else
        {
            IsCorrect ic(lr.GetId(),lr.GetPW());
            clisock = EHWrapSocket::Connect(DBM_IP,DBM_PORT);
            cout<<"패스워드 일치 확인 요청 메시지 전송"<<endl;
            ic.Serialize(clisock);

Dbm 서비스로부터 응답 메시지를 수신합니다.

            EHPacket rep3(clisock);
            closesocket(clisock);

만약 수신한 메시지가 패스워드 일치 확인 요청 응답 메시지가 아니면 오류입니다.

            if(rep3.GetMsgId() != MID_ISCORRECTACK)
            {
                cout<<"오류!!! 패스워드 일치 확인 요청 응답 메시지가 아님"<<endl;
                return;
            }

수신한 메시지를 패스워드 일치 확인 요청 응답 메시지로 변환합니다.

            IsCorrectAck ica(&rep3);

일치하지 않으면 결과를 변경합니다.

            if(ica.GetResult() == IDPW_NOTCORRECT)
            {
                result = LOGIN_RES_NOTCORRECT;
            }
        }
    }

수신한 소켓으로 로긴 요청 결과 메시지를 전송합니다.

    LogInRes lres(result);
    cout<<"로긴 요청 결과 전송"<<endl;
    lres.Serialize(sock);
}

로그 아웃 요청 메시지 처리 함수를 작성합시다.

void LogOutReqProc(SOCKET sock,EHPacket *ep)
{
    cout<<"로그 아웃 요청 수신"<<endl;
    LogOutReq lr(ep);

로그 아웃 요청 메시지를 수신하면 Log 서비스는 Dbm 서비스에 연결하여 상태 변경 요청 메시지를 전송합니다. 이 때 상태는 로긴 중(STS_LOGGING)을 전달합니다.

    ChangeSts cs(lr.GetId(), STS_LOGGING);
    SOCKET clisock = EHWrapSocket::Connect(DBM_IP,DBM_PORT);
    cout<<"상태 변경(로긴 중) 요청 메시지 전송"<<endl;
    cs.Serialize(clisock);
    closesocket(clisock);
}